From a94e1f3db5836264486b4b46fa28c71718841191 Mon Sep 17 00:00:00 2001 From: squareys Date: Thu, 3 Sep 2015 15:16:19 +0200 Subject: [PATCH 01/14] Add Implementation of MapNeighborhood for NativeType ArrayImg Signed-off-by: squareys --- .../array/MapNeighborhoodNativeType.java | 74 +++++++++++++ .../array/NeighborhoodIterableNativeType.java | 102 ++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java create mode 100644 src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java new file mode 100644 index 0000000000..acc0578e47 --- /dev/null +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java @@ -0,0 +1,74 @@ + +package net.imagej.ops.map.neighborhood.array; + +import net.imagej.ops.ComputerOp; +import net.imagej.ops.Contingent; +import net.imagej.ops.Op; +import net.imagej.ops.Ops; +import net.imagej.ops.map.AbstractMapComputer; +import net.imglib2.img.Img; +import net.imglib2.img.array.ArrayImg; +import net.imglib2.type.NativeType; + +import org.scijava.Priority; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; + +/** + * Optimized neighborhood map implementation for {@link Img}. This + * implementation uses access to the underlying types, which bypasses + * OutOfBounds checks though. This means that pixels which are out of bounds are + * not considered as belonging to the neighborhood of a pixel. This can change + * results of averages over a neighborhood in comparison to using an out of + * bounds strategy which "creates" pixels in the neighborhood where there are + * non after the bounds of the image. + * + * @author Jonathan Hale + * @param Input {@link NativeType} + * @param Ouput {@link NativeType} + */ +@Plugin(type = Op.class, name = Ops.Map.NAME, + priority = Priority.LOW_PRIORITY + 10) +public class MapNeighborhoodNativeType, O extends NativeType> + extends AbstractMapComputer, O, ArrayImg, ArrayImg> + implements Contingent +{ + + @Parameter + private int span; + + @Override + public void compute(final ArrayImg input, final ArrayImg output) { + final I in = input.firstElement(); + final O out = output.firstElement(); + + final int width = (int) input.dimension(0); + final int height = (int) input.dimension(1); + + final ComputerOp, O> op = getOp(); + + int index; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + // save the current index, since it will be changed by the + // NeighborhoodIterable. Increment to save doing that later. + index = in.getIndex() + 1; + + final Iterable neighborhood = + new NeighborhoodIterableNativeType(in, x, y, width, height, span); + + op.compute(neighborhood, out); + + in.updateIndex(index); + out.incIndex(); + } + } + } + + @Override + public boolean conforms() { + return getInput().numDimensions() == 2; + } + +} diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java new file mode 100644 index 0000000000..b3370e257e --- /dev/null +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java @@ -0,0 +1,102 @@ + +package net.imagej.ops.map.neighborhood.array; + +import java.util.Iterator; + +import net.imglib2.type.NativeType; + +/** + * Optimized rectangle neighborhood {@link Iterable} for {@link NativeType} + * which ignores out of bounds pixels. + * + * @param Type of the contents of the Iterable. + * @author Jonathan Hale + */ +final class NeighborhoodIterableNativeType> implements + Iterable +{ + + private final I pointer; + private final int neighSize; + private final int hDiameter; + private final int startIndex; + private final int nextLineSkip; + + /** + * Constructor + * + * @param pointer NativeType to use as "cursor" + * @param x Left bounds of the rectangle neighborhood + * @param y Top bounds of the rectangle neighborhood + * @param w Width of the rectangle neighborhood + * @param h Height of the rectangle neighborhood + * @param span Span of the neighborhood (to avoid redundant calculation) + */ + public NeighborhoodIterableNativeType(final I pointer, final int x, + final int y, final int w, final int h, final int span) + { + // clamp extensions in every direction to ensure we won't go out of bounds + final int left = Math.min(x, span); + final int top = Math.min(y, span); + final int right = Math.min(w - 1 - x, span); + final int bottom = Math.min(h - 1 - y, span); + + final int vDiameter = top + bottom + 1; + this.hDiameter = left + right + 1; + this.pointer = pointer; + this.neighSize = hDiameter * vDiameter; + + pointer.decIndex(top * w + left + 1); + + this.startIndex = pointer.getIndex(); + + this.nextLineSkip = w - (hDiameter - 1); + } + + @Override + public final Iterator iterator() { + return new MapNeighborhoodIterator(); + } + + /** + * Iterator over a rectangular neighborhood. + * + * @author Jonathan Hale + */ + private final class MapNeighborhoodIterator implements Iterator { + + public MapNeighborhoodIterator() { + pointer.updateIndex(startIndex); + } + + int index = 0; + int x = -1; + + @Override + public final boolean hasNext() { + return index < neighSize; + } + + @Override + public final I next() { + index++; + x++; + + if (x == hDiameter) { + // end of line, skip pixels until next line + pointer.incIndex(nextLineSkip); + x = 0; + } + else { + pointer.incIndex(); + } + + return pointer; + } + + @Override + public final void remove() { + // noop + } + } +} From 41fbc3c8e72f009c653743fc8a43099e45d27280 Mon Sep 17 00:00:00 2001 From: squareys Date: Thu, 3 Sep 2015 15:16:44 +0200 Subject: [PATCH 02/14] Add Implementation of MapNeighborhoodWithCenter for NativeType ArrayImg Signed-off-by: squareys --- .../MapNeighborhoodWithCenterNativeType.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java new file mode 100644 index 0000000000..b180587cab --- /dev/null +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java @@ -0,0 +1,81 @@ + +package net.imagej.ops.map.neighborhood.array; + +import net.imagej.ops.ComputerOp; +import net.imagej.ops.Contingent; +import net.imagej.ops.Op; +import net.imagej.ops.Ops; +import net.imagej.ops.map.AbstractMapComputer; +import net.imglib2.img.Img; +import net.imglib2.img.array.ArrayImg; +import net.imglib2.type.NativeType; +import net.imglib2.util.Pair; +import net.imglib2.util.ValuePair; + +import org.scijava.Priority; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; + +/** + * Optimized neighborhood map implementation for {@link Img}. This + * implementation uses access to the underlying types, which bypasses + * OutOfBounds checks though. This means that pixels which are out of bounds are + * not considered as belonging to the neighborhood of a pixel. This can change + * results of averages over a neighborhood in comparison to using an out of + * bounds strategy which "creates" pixels in the neighborhood where there are + * non after the bounds of the image. + * + * @author Jonathan Hale + * @param Input {@link NativeType} + * @param Ouput {@link NativeType} + */ +@Plugin(type = Op.class, name = Ops.Map.NAME, + priority = Priority.LOW_PRIORITY + 10) +public class MapNeighborhoodWithCenterNativeType, O extends NativeType> + extends + AbstractMapComputer>, O, ArrayImg, ArrayImg> + implements Contingent +{ + + @Parameter + private int span; + + @Override + public void compute(final ArrayImg input, final ArrayImg output) { + final I in = input.firstElement(); + final O out = output.firstElement(); + + final int width = (int) input.dimension(0); + final int height = (int) input.dimension(1); + + final ComputerOp>, O> op = getOp(); + + int index; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + // save the current index, since it will be changed by the + // NeighborhoodIterable. Increment to save doing that later. + index = in.getIndex() + 1; + + // copy for center pixel access, since it will get changed, again, by + // NeighborhoodIterable. + final I center = in.copy(); + + final Iterable neighborhood = + new NeighborhoodIterableNativeType(in, x, y, width, height, span); + + op.compute(new ValuePair>(center, neighborhood), out); + + in.updateIndex(index); + out.incIndex(); + } + } + } + + @Override + public boolean conforms() { + return getInput().numDimensions() == 2; + } + +} From bd20d98b87346e585d91ebb4ed812b11ba2627d9 Mon Sep 17 00:00:00 2001 From: squareys Date: Thu, 3 Sep 2015 15:17:35 +0200 Subject: [PATCH 03/14] Add op methods for optimized neighborhood map implementations Signed-off-by: squareys --- .../net/imagej/ops/AbstractOpEnvironment.java | 28 +++++++++++++++++++ .../java/net/imagej/ops/OpEnvironment.java | 18 ++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java index f237b4dba6..44b560fe93 100644 --- a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java +++ b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java @@ -55,6 +55,8 @@ import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.neighborhood.Shape; +import net.imglib2.img.array.ArrayImg; +import net.imglib2.type.NativeType; import net.imglib2.type.Type; import net.imglib2.type.numeric.RealType; @@ -506,6 +508,32 @@ public RandomAccessibleInterval map( return result; } + @Override + public , O extends NativeType> ArrayImg map( + final ArrayImg out, final ArrayImg in, + final CenterAwareComputerOp op, final Integer span) + { + @SuppressWarnings("unchecked") + final ArrayImg result = + (ArrayImg) run( + net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType.class, + out, in, op, span); + return result; + } + + @Override + public , O extends NativeType> ArrayImg map( + final ArrayImg out, final ArrayImg in, + final ComputerOp, O> op, final Integer span) + { + @SuppressWarnings("unchecked") + final ArrayImg result = + (ArrayImg) run( + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class, + out, in, op, span); + return result; + } + @Override public Iterable map(final Iterable out, final Iterable in, final ComputerOp op) diff --git a/src/main/java/net/imagej/ops/OpEnvironment.java b/src/main/java/net/imagej/ops/OpEnvironment.java index bf4eec3e82..7e0f4bcb38 100644 --- a/src/main/java/net/imagej/ops/OpEnvironment.java +++ b/src/main/java/net/imagej/ops/OpEnvironment.java @@ -51,7 +51,11 @@ import net.imglib2.IterableInterval; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.algorithm.neighborhood.RectangleShape; import net.imglib2.algorithm.neighborhood.Shape; +import net.imglib2.img.array.ArrayImg; +import net.imglib2.outofbounds.OutOfBoundsFactory; +import net.imglib2.type.NativeType; import net.imglib2.type.Type; import net.imglib2.type.numeric.RealType; @@ -399,6 +403,20 @@ RandomAccessibleInterval map(RandomAccessibleInterval out, RandomAccessibleInterval in, CenterAwareComputerOp, O> op, Shape shape); + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType.class) + , O extends NativeType> ArrayImg map( + ArrayImg out, ArrayImg in, CenterAwareComputerOp op, + Integer span); + + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class) + , O extends NativeType> ArrayImg map( + ArrayImg out, ArrayImg in, ComputerOp, O> op, + Integer span); + /** Executes the "map" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.map.MapIterableToIterable.class) Iterable map(Iterable out, Iterable in, ComputerOp op); From 610e5e73ffac4e3656cb6d1f531d20d1af44e324 Mon Sep 17 00:00:00 2001 From: squareys Date: Thu, 3 Sep 2015 15:17:52 +0200 Subject: [PATCH 04/14] Test optimized neighborhood map implementations Signed-off-by: squareys --- .../map/neighborhood/MapNeighborhoodTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java index a1d55407b9..e91264b759 100644 --- a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java +++ b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java @@ -6,6 +6,8 @@ import net.imagej.ops.AbstractComputerOp; import net.imagej.ops.AbstractOpTest; import net.imagej.ops.Op; +import net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType; +import net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType; import net.imglib2.algorithm.neighborhood.RectangleShape; import net.imglib2.img.Img; import net.imglib2.type.numeric.integer.ByteType; @@ -83,6 +85,58 @@ public void testMapNeighborhoodsWithCenterAccess() { } } + /** + * Test if every neighborhood pixel of the image was really accessed during + * the map operation. + * + * @see MapNeighborhoodNativeType + */ + @Test + public void testMapNeighborhoodsArrayImage() { + final Op functional = + ops.op(MapNeighborhoodNativeType.class, out, in, + new CountNeighborsWithAccess(), 1); + functional.run(); + + final byte[] expected = + new byte[] { 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, + 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4 }; + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index + ": ", expected[index++], t.get()); + } + } + + /** + * Test if every neighborhood pixel of the image was really accessed during + * the map operation. + * + * @see MapNeighborhoodWithCenterNativeType + */ + @Test + public void testMapNeighborhoodsWithCenterAccessArrayImage() { + final Op functional = + ops.op(MapNeighborhoodWithCenterNativeType.class, out, in, + new CountNeighborsWithAccessWithCenter(), 1); + functional.run(); + + final byte[] expected = + new byte[] { 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, + 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4 }; + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index + ": ", expected[index++], t.get()); + } + } + /** * Function which increments the output value for every pixel in the * neighborhood. From 57d4e929d79ab1e9c93a2d9bd71c61159061dd18 Mon Sep 17 00:00:00 2001 From: squareys Date: Fri, 4 Sep 2015 12:57:22 +0200 Subject: [PATCH 05/14] Expand optimized implementation to 1D and 3D NativeType ArrayImgs To avoid code duplication, I decided to expand the existing implementation rather than implementing a new Op for 3D/1D. While this may not be "optimal peformance", the maintainability outweights the minimal and probably unsignificant "performance loss". Signed-off-by: squareys --- .../array/MapNeighborhoodNativeType.java | 39 ++++++---- .../MapNeighborhoodWithCenterNativeType.java | 49 ++++++------ .../array/NeighborhoodIterableNativeType.java | 77 ++++++++++++++++--- 3 files changed, 117 insertions(+), 48 deletions(-) diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java index acc0578e47..157b2eacbb 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java @@ -15,17 +15,18 @@ import org.scijava.plugin.Plugin; /** - * Optimized neighborhood map implementation for {@link Img}. This + * Optimized neighborhood map implementation for 1D/2D/3D {@link Img}. This * implementation uses access to the underlying types, which bypasses - * OutOfBounds checks though. This means that pixels which are out of bounds are - * not considered as belonging to the neighborhood of a pixel. This can change - * results of averages over a neighborhood in comparison to using an out of - * bounds strategy which "creates" pixels in the neighborhood where there are - * non after the bounds of the image. + * OutOfBounds checks, though. This means that pixels which are out of bounds + * are not considered as belonging to the neighborhood of a pixel. This can + * change results of averages over a neighborhood in comparison to using an out + * of bounds strategy which "creates" pixels in the neighborhood where there are + * none after the bounds of the image. * * @author Jonathan Hale * @param Input {@link NativeType} * @param Ouput {@link NativeType} + * @see MapNeighborhoodWithCenterNativeType */ @Plugin(type = Op.class, name = Ops.Map.NAME, priority = Priority.LOW_PRIORITY + 10) @@ -44,31 +45,35 @@ public void compute(final ArrayImg input, final ArrayImg output) { final int width = (int) input.dimension(0); final int height = (int) input.dimension(1); + final int depth = Math.max(0, (int) input.dimension(2)); final ComputerOp, O> op = getOp(); int index; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - // save the current index, since it will be changed by the - // NeighborhoodIterable. Increment to save doing that later. - index = in.getIndex() + 1; + for (int z = 0; z < depth; ++z) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + // save the current index, since it will be changed by the + // NeighborhoodIterable. Increment to save doing that later. + index = in.getIndex() + 1; - final Iterable neighborhood = - new NeighborhoodIterableNativeType(in, x, y, width, height, span); + final Iterable neighborhood = + new NeighborhoodIterableNativeType(in, x, y, z, width, height, + depth, span); - op.compute(neighborhood, out); + op.compute(neighborhood, out); - in.updateIndex(index); - out.incIndex(); + in.updateIndex(index); + out.incIndex(); + } } } } @Override public boolean conforms() { - return getInput().numDimensions() == 2; + return getInput().numDimensions() > 0 || getInput().numDimensions() <= 3; } } diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java index b180587cab..94d7d8654a 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java @@ -17,17 +17,18 @@ import org.scijava.plugin.Plugin; /** - * Optimized neighborhood map implementation for {@link Img}. This - * implementation uses access to the underlying types, which bypasses - * OutOfBounds checks though. This means that pixels which are out of bounds are - * not considered as belonging to the neighborhood of a pixel. This can change - * results of averages over a neighborhood in comparison to using an out of - * bounds strategy which "creates" pixels in the neighborhood where there are - * non after the bounds of the image. + * Optimized center aware neighborhood map implementation for 1D/2D/3D + * {@link Img}. This implementation uses access to the underlying types, which + * bypasses OutOfBounds checks, though. This means that pixels which are out of + * bounds are not considered as belonging to the neighborhood of a pixel. This + * can change results of averages over a neighborhood in comparison to using an + * out of bounds strategy which "creates" pixels in the neighborhood where there + * are none after the bounds of the image. * * @author Jonathan Hale * @param Input {@link NativeType} * @param Ouput {@link NativeType} + * @see MapNeighborhoodNativeType */ @Plugin(type = Op.class, name = Ops.Map.NAME, priority = Priority.LOW_PRIORITY + 10) @@ -47,35 +48,39 @@ public void compute(final ArrayImg input, final ArrayImg output) { final int width = (int) input.dimension(0); final int height = (int) input.dimension(1); + final int depth = Math.max(1, (int) input.dimension(2)); final ComputerOp>, O> op = getOp(); - + int index; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - // save the current index, since it will be changed by the - // NeighborhoodIterable. Increment to save doing that later. - index = in.getIndex() + 1; + for (int z = 0; z < depth; ++z) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + // save the current index, since it will be changed by the + // NeighborhoodIterable. Increment to save doing that later. + index = in.getIndex() + 1; - // copy for center pixel access, since it will get changed, again, by - // NeighborhoodIterable. - final I center = in.copy(); + // copy for center pixel access, since it will get changed, again, by + // NeighborhoodIterable. + final I center = in.copy(); - final Iterable neighborhood = - new NeighborhoodIterableNativeType(in, x, y, width, height, span); + final Iterable neighborhood = + new NeighborhoodIterableNativeType(in, x, y, z, width, height, + depth, span); - op.compute(new ValuePair>(center, neighborhood), out); + op.compute(new ValuePair>(center, neighborhood), out); - in.updateIndex(index); - out.incIndex(); + in.updateIndex(index); + out.incIndex(); + } } } } @Override public boolean conforms() { - return getInput().numDimensions() == 2; + return getInput().numDimensions() > 0 || getInput().numDimensions() <= 3; } } diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java index b3370e257e..6bbdf15fdd 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/NeighborhoodIterableNativeType.java @@ -19,8 +19,13 @@ final class NeighborhoodIterableNativeType> implements private final I pointer; private final int neighSize; private final int hDiameter; + private final int vDiameter; private final int startIndex; private final int nextLineSkip; + private final int nextSliceSkip; + + /* whether this is a 3D neighborhood */ + private final boolean volume; /** * Constructor @@ -28,34 +33,81 @@ final class NeighborhoodIterableNativeType> implements * @param pointer NativeType to use as "cursor" * @param x Left bounds of the rectangle neighborhood * @param y Top bounds of the rectangle neighborhood + * @param z Front bounds of the rectangle neighborhood * @param w Width of the rectangle neighborhood * @param h Height of the rectangle neighborhood + * @param d Depth of the rectangle neighborhood * @param span Span of the neighborhood (to avoid redundant calculation) */ public NeighborhoodIterableNativeType(final I pointer, final int x, - final int y, final int w, final int h, final int span) + final int y, final int z, final int w, final int h, final int d, + final int span) { // clamp extensions in every direction to ensure we won't go out of bounds final int left = Math.min(x, span); final int top = Math.min(y, span); final int right = Math.min(w - 1 - x, span); final int bottom = Math.min(h - 1 - y, span); + final int front = Math.min(z, span); + final int back = Math.min(d - 1 - z, span); - final int vDiameter = top + bottom + 1; this.hDiameter = left + right + 1; + this.vDiameter = top + bottom + 1; + final int dDiameter = back + front + 1; this.pointer = pointer; - this.neighSize = hDiameter * vDiameter; + this.neighSize = hDiameter * vDiameter * dDiameter; - pointer.decIndex(top * w + left + 1); + pointer.decIndex(front * w * h + top * w + left + 1); this.startIndex = pointer.getIndex(); this.nextLineSkip = w - (hDiameter - 1); + this.nextSliceSkip = (h - vDiameter) * hDiameter; + + this.volume = vDiameter != 1; } @Override public final Iterator iterator() { - return new MapNeighborhoodIterator(); + return (volume) ? new MapNeighborhoodIterator3D() + : new MapNeighborhoodIterator2D(); + } + + /** + * Iterator over a rectangular neighborhood. + * + * @author Jonathan Hale + */ + private final class MapNeighborhoodIterator2D implements Iterator { + + public MapNeighborhoodIterator2D() { + pointer.updateIndex(startIndex); + } + + int index = 0; + int x = -1; + + @Override + public final boolean hasNext() { + return index < neighSize; + } + + @Override + public final I next() { + ++index; + ++x; + + if (x == hDiameter) { + // end of line, skip pixels until next line + pointer.incIndex(nextLineSkip); + x = 0; + } + else { + pointer.incIndex(); + } + + return pointer; + } } /** @@ -63,14 +115,15 @@ public final Iterator iterator() { * * @author Jonathan Hale */ - private final class MapNeighborhoodIterator implements Iterator { + private final class MapNeighborhoodIterator3D implements Iterator { - public MapNeighborhoodIterator() { + public MapNeighborhoodIterator3D() { pointer.updateIndex(startIndex); } int index = 0; int x = -1; + int y = -1; @Override public final boolean hasNext() { @@ -79,13 +132,19 @@ public final boolean hasNext() { @Override public final I next() { - index++; - x++; + ++index; + ++x; if (x == hDiameter) { // end of line, skip pixels until next line pointer.incIndex(nextLineSkip); x = 0; + ++y; + if (y == vDiameter) { + // end of slice, skip pixels until next slice + pointer.incIndex(nextSliceSkip); + y = 0; + } } else { pointer.incIndex(); From 27175ef10a79b8bbf7ab382af103dbc52dd94a21 Mon Sep 17 00:00:00 2001 From: squareys Date: Fri, 4 Sep 2015 12:57:40 +0200 Subject: [PATCH 06/14] Test optimized 1D and 3D neighborhood map implementations Signed-off-by: squareys --- .../map/neighborhood/MapNeighborhoodTest.java | 59 +++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java index e91264b759..5aa92c0a45 100644 --- a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java +++ b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java @@ -86,13 +86,13 @@ public void testMapNeighborhoodsWithCenterAccess() { } /** - * Test if every neighborhood pixel of the image was really accessed during + * Test if every neighborhood pixel of the 2D image was really accessed during * the map operation. * * @see MapNeighborhoodNativeType */ @Test - public void testMapNeighborhoodsArrayImage() { + public void testMapNeighborhoodsArrayImage2D() { final Op functional = ops.op(MapNeighborhoodNativeType.class, out, in, new CountNeighborsWithAccess(), 1); @@ -110,15 +110,66 @@ public void testMapNeighborhoodsArrayImage() { assertEquals("Index " + index + ": ", expected[index++], t.get()); } } + + /** + * Test if every neighborhood pixel of the 1D image was really accessed during + * the map operation. + * + * @see MapNeighborhoodNativeType + */ + @Test + public void testMapNeighborhoodsArrayImage1D() { + in = generateByteTestImg(true, 7); + out = generateByteTestImg(false, 7); + + final Op functional = + ops.op(MapNeighborhoodNativeType.class, out, in, + new CountNeighborsWithAccess(), 1); + functional.run(); + + final byte[] expected = + new byte[] { 2, 3, 3, 3, 3, 3, 2 }; + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index + ": ", expected[index++], t.get()); + } + } /** - * Test if every neighborhood pixel of the image was really accessed during + * Test if every neighborhood pixel of the 3D image was really accessed during + * the map operation. + * + * @see MapNeighborhoodNativeType + */ + @Test + public void testMapNeighborhoodsArrayImage3D() { + in = generateByteTestImg(true, 3, 3, 3); + out = generateByteTestImg(false, 3, 3, 3); + + final Op functional = + ops.op(MapNeighborhoodNativeType.class, out, in, + new CountNeighborsWithAccess(), 1); + functional.run(); + + final byte[] expected = + new byte[] { 8, 12, 8, 12, 18, 12, 8, 12, 8, 12, 18, 12, 18, 27, 18, 12, + 18, 12, 8, 12, 8, 12, 18, 12, 8, 12, 8 }; + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index + ": ", expected[index++], t.get()); + } + } + + /** + * Test if every neighborhood pixel of the 2D image was really accessed during * the map operation. * * @see MapNeighborhoodWithCenterNativeType */ @Test - public void testMapNeighborhoodsWithCenterAccessArrayImage() { + public void testMapNeighborhoodsWithCenterAccessArrayImage2D() { final Op functional = ops.op(MapNeighborhoodWithCenterNativeType.class, out, in, new CountNeighborsWithAccessWithCenter(), 1); From bc98ba5a9786fd5b6bcd87c774b669aa19575d5a Mon Sep 17 00:00:00 2001 From: squareys Date: Fri, 4 Sep 2015 13:04:21 +0200 Subject: [PATCH 07/14] Fix MapNeighborhoodWithCenterNativeType superclass Signed-off-by: squareys --- .../array/MapNeighborhoodWithCenterNativeType.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java index 94d7d8654a..d730d19031 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodWithCenterNativeType.java @@ -1,15 +1,14 @@ package net.imagej.ops.map.neighborhood.array; -import net.imagej.ops.ComputerOp; import net.imagej.ops.Contingent; import net.imagej.ops.Op; import net.imagej.ops.Ops; -import net.imagej.ops.map.AbstractMapComputer; +import net.imagej.ops.map.neighborhood.AbstractMapCenterAwareComputer; +import net.imagej.ops.map.neighborhood.CenterAwareComputerOp; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImg; import net.imglib2.type.NativeType; -import net.imglib2.util.Pair; import net.imglib2.util.ValuePair; import org.scijava.Priority; @@ -33,8 +32,7 @@ @Plugin(type = Op.class, name = Ops.Map.NAME, priority = Priority.LOW_PRIORITY + 10) public class MapNeighborhoodWithCenterNativeType, O extends NativeType> - extends - AbstractMapComputer>, O, ArrayImg, ArrayImg> + extends AbstractMapCenterAwareComputer, ArrayImg> implements Contingent { @@ -50,7 +48,7 @@ public void compute(final ArrayImg input, final ArrayImg output) { final int height = (int) input.dimension(1); final int depth = Math.max(1, (int) input.dimension(2)); - final ComputerOp>, O> op = getOp(); + final CenterAwareComputerOp op = getOp(); int index; From 26df6e395832e547d1bd7848509030d76edf5aae Mon Sep 17 00:00:00 2001 From: squareys Date: Mon, 7 Sep 2015 14:02:46 +0200 Subject: [PATCH 08/14] Add an op which wraps input to MapNeighborhood to input to optimized... ... implementation `MapNeighborhoodNativeType`. This was requested to be able to let OpService choose the optimized implementation implicitly. There is however some performance loss which is hopefully traded off by using multiple threads. Signed-off-by: squareys --- .../MapNeighborhoodNativeTypeExtended.java | 241 ++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java new file mode 100644 index 0000000000..9b39071adf --- /dev/null +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java @@ -0,0 +1,241 @@ + +package net.imagej.ops.map.neighborhood.array; + +import java.util.ArrayList; +import java.util.concurrent.Future; + +import net.imagej.ops.Contingent; +import net.imagej.ops.Op; +import net.imagej.ops.OpService; +import net.imagej.ops.Ops; +import net.imagej.ops.map.AbstractMapComputer; +import net.imagej.ops.map.neighborhood.MapNeighborhood; +import net.imglib2.FinalInterval; +import net.imglib2.algorithm.neighborhood.CenteredRectangleShape; +import net.imglib2.algorithm.neighborhood.Neighborhood; +import net.imglib2.img.array.ArrayImg; +import net.imglib2.outofbounds.OutOfBoundsFactory; +import net.imglib2.type.NativeType; +import net.imglib2.view.Views; + +import org.scijava.Cancelable; +import org.scijava.Priority; +import org.scijava.log.LogService; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.thread.ThreadService; + +/** + * Optimized implementation of MapNeighborhood which uses + * {@link MapNeighborhoodNativeType} for a center interval which does not + * require out of bounds checks and {@link MapNeighborhood} for external + * intervals. + * + * @author Jonathan Hale + * @param Input {@link NativeType} + * @param Ouput {@link NativeType} + * @see MapNeighborhoodWithCenterNativeType + * @see MapNeighborhood + */ +@Plugin(type = Op.class, name = Ops.Map.NAME, + priority = Priority.LOW_PRIORITY + 10) +public class MapNeighborhoodNativeTypeExtended, O extends NativeType> + extends AbstractMapComputer, O, ArrayImg, ArrayImg> + implements Contingent, Cancelable +{ + + @Parameter + protected ThreadService threadService; + + @Parameter + protected OpService ops; + + @Parameter + protected LogService log; + + @Parameter + private CenteredRectangleShape shape; + + @Parameter(required = false) + private OutOfBoundsFactory oobFactory; + + @Override + public void compute(final ArrayImg input, final ArrayImg output) { + // all dimensions are equal as ensured in conforms() */ + final int span = + (int) ((shape.neighborhoodsRandomAccessible(input).randomAccess().get() + .dimension(0) - 1) / 2); + + final int numDimensions = input.numDimensions(); + + // calculate intervals + FinalInterval[] intervals; + FinalInterval center; + final long dim0 = input.dimension(0); + final long max0 = dim0 - span - 1; // maximal extension of horizonally + // centered intervals + + /* Note about ordering of intervals: + * Since done parallel, the idea is to queue work by decreasing size. + * The center interval is usually the biggest, but can be best optimized. + * Following: front/back, top/bottom, left/right. (Depending on dimensions, + * some might not be available.) + * + * The intervals were chosen intentionally to optimize access to storage, + * which is expected to be in order of dimensions (0 first, then 1, ...). + * + * The order for queuing the tasks is: Unoptimized intervals in order of size, + * then optimized center interval + */ + /* build intervals */ + if (numDimensions == 1) { + intervals = new FinalInterval[] { + /* left */ + new FinalInterval(new long[] { 0 }, new long[] { span }), + /* right */ + new FinalInterval(new long[] { dim0 - span }, new long[] { span }) }; + /* center */ + center = new FinalInterval(new long[] { span + 1 }, new long[] { max0 }); + } + else if (numDimensions == 2) { + final long dim1 = input.dimension(1); + final long max1 = dim1 - span - 1; // maximal extension of vertically + // centered intervals + + intervals = + new FinalInterval[] { + /* top */ + new FinalInterval(new long[] { 0, 0 }, new long[] { dim0, span }), + /* bottom */ + new FinalInterval(new long[] { 0, dim1 - span }, new long[] { dim0, + dim1 }), + /* left */ + new FinalInterval(new long[] { 0, span + 1 }, + new long[] { span, span }), + /* right */ + new FinalInterval(new long[] { dim0 - span, span + 1 }, new long[] { + span, max1 }), }; + /* center */ + center = + new FinalInterval(new long[] { span + 1, span + 1 }, new long[] { max0, + max1 }); + } + else { + // numDimensions == 3, guranteed by conforms() + + final long dim1 = input.dimension(1); + final long dim2 = input.dimension(2); + final long max1 = dim1 - span - 1; // maximal extension of vertically + // centered intervals + final long max2 = dim2 - span - 1; // maximal extension of depth centered + // intervals + final long spanPlus1 = span + 1; + + intervals = + new FinalInterval[] { + new FinalInterval(new long[] { 0, 0 }, + /* front */ + new long[] { dim0, dim1, span }), + /* back */ + new FinalInterval(new long[] { 0, 0, dim2 - span }, new long[] { + dim0, dim1, dim2 }), + /* top */ + new FinalInterval(new long[] { 0, 0, spanPlus1 }, new long[] { dim0, + span, max2 }), + /* bottom */ + new FinalInterval(new long[] { 0, dim1 - span, spanPlus1 }, + new long[] { dim0, dim1, max2 }), + /* left */ + new FinalInterval(new long[] { 0, spanPlus1, spanPlus1 }, new long[] { + span, span, max2 }), + /* right */ + new FinalInterval(new long[] { dim0 - span, spanPlus1 }, new long[] { + span, max1, max2 }), }; + /* center */ + center = + new FinalInterval(new long[] { spanPlus1, spanPlus1, spanPlus1 }, + new long[] { max0, max1, max2 }); + } + + ArrayList> futures = + new ArrayList>(2 * numDimensions + 1); + + for (final FinalInterval interval : intervals) { + futures.add(threadService.run(new Runnable() { + + @Override + public void run() { + ops.run(MapNeighborhood.class, Views.interval(output, interval), + Views.interval(input, interval), getOp(), shape, oobFactory); + } + })); + } + + final FinalInterval finalCenter = center; + futures.add(threadService.run(new Runnable() { + + @Override + public void run() { + ops.map(Views.interval(output, finalCenter), Views.interval(input, + finalCenter), getOp(), span); + } + })); + + // wait for tasks to complete + for (final Future future : futures) { + try { + if (isCanceled()) { + break; + } + future.get(); + } + catch (final Exception e) { + log.error(e); + cancel(e.getMessage()); + break; + } + } + } + + @Override + public boolean conforms() { + if (!(getInput().numDimensions() > 0 || getInput().numDimensions() <= 3)) { + return false; + } + + /* all dimensions of the neighborhood have to be equal to be able to use + MapNeighborhoodNativeType */ + Neighborhood neighborhood = + shape.neighborhoodsRandomAccessible(getInput()).randomAccess().get(); + final long dimension0 = neighborhood.dimension(0); + + for (int i = 1; i < neighborhood.numDimensions(); ++i) { + if (dimension0 != neighborhood.dimension(i)) { + return false; + } + } + + return true; + } + + // --- Cancelable methods --- + + private String cancelReason = null; + private boolean canceled; + + @Override + public boolean isCanceled() { + return canceled; + } + + @Override + public void cancel(String reason) { + cancelReason = reason; + canceled = true; + } + + @Override + public String getCancelReason() { + return cancelReason; + } +} From 8d5cb4db91b3270f60c57554fba8077d03f8188e Mon Sep 17 00:00:00 2001 From: squareys Date: Tue, 15 Sep 2015 11:25:56 +0200 Subject: [PATCH 09/14] Add MapNeighborhoodNativeTypeExtended This Op provides the same interface as all the other MapNeighborhood Ops and therefore makes the optimized implementation of MapNeighborhood for NativeType (namely `MapNeighborhoodNativeType`) available for implicit optimization of depending algorithms. Signed-off-by: squareys --- .../net/imagej/ops/AbstractOpEnvironment.java | 28 +++++ .../java/net/imagej/ops/OpEnvironment.java | 16 +++ .../array/MapNeighborhoodNativeType.java | 70 ++++++++++-- .../MapNeighborhoodNativeTypeExtended.java | 105 ++++++++---------- .../map/neighborhood/MapNeighborhoodTest.java | 23 ++++ 5 files changed, 178 insertions(+), 64 deletions(-) diff --git a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java index 44b560fe93..954f9d4e91 100644 --- a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java +++ b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java @@ -54,8 +54,10 @@ import net.imglib2.IterableInterval; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.algorithm.neighborhood.RectangleShape; import net.imglib2.algorithm.neighborhood.Shape; import net.imglib2.img.array.ArrayImg; +import net.imglib2.outofbounds.OutOfBoundsFactory; import net.imglib2.type.NativeType; import net.imglib2.type.Type; import net.imglib2.type.numeric.RealType; @@ -534,6 +536,32 @@ public RandomAccessibleInterval map( return result; } + @Override + public , O extends NativeType> ArrayImg map( + ArrayImg out, ArrayImg in, ComputerOp, O> op, + RectangleShape shape) + { + @SuppressWarnings("unchecked") + final ArrayImg result = + (ArrayImg) run( + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class, + out, in, op, shape); + return result; + } + + @Override + public , O extends NativeType> ArrayImg map( + ArrayImg out, ArrayImg in, ComputerOp, O> op, + RectangleShape shape, OutOfBoundsFactory oobFactory) + { + @SuppressWarnings("unchecked") + final ArrayImg result = + (ArrayImg) run( + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class, + out, in, op, shape, oobFactory); + return result; + } + @Override public Iterable map(final Iterable out, final Iterable in, final ComputerOp op) diff --git a/src/main/java/net/imagej/ops/OpEnvironment.java b/src/main/java/net/imagej/ops/OpEnvironment.java index 7e0f4bcb38..2067e4c4fe 100644 --- a/src/main/java/net/imagej/ops/OpEnvironment.java +++ b/src/main/java/net/imagej/ops/OpEnvironment.java @@ -417,6 +417,22 @@ RandomAccessibleInterval map(RandomAccessibleInterval out, ArrayImg out, ArrayImg in, ComputerOp, O> op, Integer span); + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class) + public + , O extends NativeType> ArrayImg map( + ArrayImg out, ArrayImg in, ComputerOp, O> op, + RectangleShape shape); + + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class) + public + , O extends NativeType> ArrayImg map( + ArrayImg out, ArrayImg in, ComputerOp, O> op, + RectangleShape shape, OutOfBoundsFactory oobFactory); + /** Executes the "map" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.map.MapIterableToIterable.class) Iterable map(Iterable out, Iterable in, ComputerOp op); diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java index 157b2eacbb..e67a45770c 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeType.java @@ -6,6 +6,8 @@ import net.imagej.ops.Op; import net.imagej.ops.Ops; import net.imagej.ops.map.AbstractMapComputer; +import net.imglib2.FinalInterval; +import net.imglib2.Interval; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImg; import net.imglib2.type.NativeType; @@ -35,25 +37,51 @@ public class MapNeighborhoodNativeType, O extends Native implements Contingent { + /** + * Span of the centered rectangle shape to use. + */ @Parameter private int span; + /** + * Interval for input and output images to constrain interation to. + */ + @Parameter(required = false) + private Interval interval; + @Override public void compute(final ArrayImg input, final ArrayImg output) { final I in = input.firstElement(); final O out = output.firstElement(); final int width = (int) input.dimension(0); - final int height = (int) input.dimension(1); - final int depth = Math.max(0, (int) input.dimension(2)); + final int height = + (input.numDimensions() > 1) ? (int) input.dimension(1) : 1; + final int depth = + (input.numDimensions() > 2) ? (int) input.dimension(2) : 1; - final ComputerOp, O> op = getOp(); + final Interval i = (interval == null) ? input : interval; + + final int minX = (int) i.min(0); + final int minY = (i.numDimensions() > 1) ? (int) i.min(1) : 0; + final int minZ = (i.numDimensions() > 2) ? (int) i.min(2) : 0; + + final int maxX = (int) i.max(0); + final int maxY = (i.numDimensions() > 1) ? (int) i.max(1) : 0; + final int maxZ = (i.numDimensions() > 2) ? (int) i.max(2) : 0; - int index; + final int skipX = width - (maxX - minX + 1); + final int skipY = width * (height - (maxY - minY + 1)); - for (int z = 0; z < depth; ++z) { - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { + final ComputerOp, O> op = getOp(); + + int index = minX + minY * width + minZ * height * width; + in.updateIndex(index); + out.updateIndex(index); + + for (int z = minZ; z <= maxZ; ++z) { + for (int y = minY; y <= maxY; ++y) { + for (int x = minX; x <= maxX; ++x) { // save the current index, since it will be changed by the // NeighborhoodIterable. Increment to save doing that later. index = in.getIndex() + 1; @@ -67,10 +95,38 @@ public void compute(final ArrayImg input, final ArrayImg output) { in.updateIndex(index); out.incIndex(); } + in.incIndex(skipX); + out.incIndex(skipX); } + in.incIndex(skipY); + out.incIndex(skipY); } } + /** + * @return The interval which constraints iteration or null, if + * none is set. + */ + public Interval getInterval() { + return interval; + } + + /** + * Set the interval which constraints iteration. + */ + public void setInterval(Interval i) { + interval = i; + } + + /** + * Convenience method to set the interval which constraints iteration. + * + * @see #setInterval(Interval) + */ + public void setInterval(long[] min, long[] max) { + interval = new FinalInterval(min, max); + } + @Override public boolean conforms() { return getInput().numDimensions() > 0 || getInput().numDimensions() <= 3; diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java index 9b39071adf..a35911fc7b 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java @@ -11,8 +11,7 @@ import net.imagej.ops.map.AbstractMapComputer; import net.imagej.ops.map.neighborhood.MapNeighborhood; import net.imglib2.FinalInterval; -import net.imglib2.algorithm.neighborhood.CenteredRectangleShape; -import net.imglib2.algorithm.neighborhood.Neighborhood; +import net.imglib2.algorithm.neighborhood.RectangleShape; import net.imglib2.img.array.ArrayImg; import net.imglib2.outofbounds.OutOfBoundsFactory; import net.imglib2.type.NativeType; @@ -54,7 +53,7 @@ public class MapNeighborhoodNativeTypeExtended, O extend protected LogService log; @Parameter - private CenteredRectangleShape shape; + private RectangleShape shape; @Parameter(required = false) private OutOfBoundsFactory oobFactory; @@ -62,9 +61,7 @@ public class MapNeighborhoodNativeTypeExtended, O extend @Override public void compute(final ArrayImg input, final ArrayImg output) { // all dimensions are equal as ensured in conforms() */ - final int span = - (int) ((shape.neighborhoodsRandomAccessible(input).randomAccess().get() - .dimension(0) - 1) / 2); + final int span = shape.getSpan(); final int numDimensions = input.numDimensions(); @@ -72,9 +69,10 @@ public void compute(final ArrayImg input, final ArrayImg output) { FinalInterval[] intervals; FinalInterval center; final long dim0 = input.dimension(0); - final long max0 = dim0 - span - 1; // maximal extension of horizonally + final long max0 = input.max(0); + final long maxSafe0 = max0 - span; // maximal extension of horizontally // centered intervals - + final long spanPlus1 = span + 1; /* Note about ordering of intervals: * Since done parallel, the idea is to queue work by decreasing size. * The center interval is usually the biggest, but can be best optimized. @@ -93,68 +91,69 @@ public void compute(final ArrayImg input, final ArrayImg output) { /* left */ new FinalInterval(new long[] { 0 }, new long[] { span }), /* right */ - new FinalInterval(new long[] { dim0 - span }, new long[] { span }) }; + new FinalInterval(new long[] { dim0 - span }, new long[] { max0 }) }; /* center */ - center = new FinalInterval(new long[] { span + 1 }, new long[] { max0 }); + center = + new FinalInterval(new long[] { spanPlus1 }, new long[] { maxSafe0 }); } else if (numDimensions == 2) { final long dim1 = input.dimension(1); - final long max1 = dim1 - span - 1; // maximal extension of vertically + final long max1 = input.max(1); + final long maxSafe1 = max1 - span; // maximal extension of vertically // centered intervals intervals = new FinalInterval[] { /* top */ - new FinalInterval(new long[] { 0, 0 }, new long[] { dim0, span }), + new FinalInterval(new long[] { 0, 0 }, new long[] { max0, span }), /* bottom */ - new FinalInterval(new long[] { 0, dim1 - span }, new long[] { dim0, - dim1 }), + new FinalInterval(new long[] { 0, dim1 - span }, new long[] { max0, + max1 }), /* left */ - new FinalInterval(new long[] { 0, span + 1 }, - new long[] { span, span }), + new FinalInterval(new long[] { 0, spanPlus1 }, new long[] { span, + max1 - span }), /* right */ - new FinalInterval(new long[] { dim0 - span, span + 1 }, new long[] { - span, max1 }), }; + new FinalInterval(new long[] { dim0 - span, spanPlus1 }, new long[] { + max0, maxSafe1 }) }; /* center */ center = - new FinalInterval(new long[] { span + 1, span + 1 }, new long[] { max0, - max1 }); + new FinalInterval(new long[] { spanPlus1, spanPlus1 }, new long[] { + maxSafe0, maxSafe1 }); } else { - // numDimensions == 3, guranteed by conforms() + // numDimensions == 3, guaranteed by conforms() final long dim1 = input.dimension(1); final long dim2 = input.dimension(2); - final long max1 = dim1 - span - 1; // maximal extension of vertically + final long max1 = input.max(1); + final long max2 = input.max(2); + final long maxSafe1 = max1 - span; // maximal extension of vertically + // centered intervals + final long maxSafe2 = max2 - span; // maximal extension of depth // centered intervals - final long max2 = dim2 - span - 1; // maximal extension of depth centered - // intervals - final long spanPlus1 = span + 1; - intervals = new FinalInterval[] { - new FinalInterval(new long[] { 0, 0 }, /* front */ - new long[] { dim0, dim1, span }), + new FinalInterval(new long[] { 0, 0, 0 }, new long[] { max0, max1, span }), /* back */ new FinalInterval(new long[] { 0, 0, dim2 - span }, new long[] { - dim0, dim1, dim2 }), + max0, max1, max2 }), /* top */ - new FinalInterval(new long[] { 0, 0, spanPlus1 }, new long[] { dim0, - span, max2 }), + new FinalInterval(new long[] { 0, 0, spanPlus1 }, new long[] { max0, + span, maxSafe2 }), /* bottom */ new FinalInterval(new long[] { 0, dim1 - span, spanPlus1 }, - new long[] { dim0, dim1, max2 }), + new long[] { max0, max1, maxSafe2 }), /* left */ new FinalInterval(new long[] { 0, spanPlus1, spanPlus1 }, new long[] { - span, span, max2 }), + span, maxSafe1, maxSafe2 }), /* right */ - new FinalInterval(new long[] { dim0 - span, spanPlus1 }, new long[] { - span, max1, max2 }), }; + new FinalInterval(new long[] { dim0 - span, spanPlus1, spanPlus1 }, new long[] { + max0, maxSafe1, maxSafe2 }) }; /* center */ center = new FinalInterval(new long[] { spanPlus1, spanPlus1, spanPlus1 }, - new long[] { max0, max1, max2 }); + new long[] { maxSafe0, maxSafe1, maxSafe2 }); } ArrayList> futures = @@ -165,10 +164,17 @@ else if (numDimensions == 2) { @Override public void run() { - ops.run(MapNeighborhood.class, Views.interval(output, interval), - Views.interval(input, interval), getOp(), shape, oobFactory); + if (oobFactory == null) { + ops.run(MapNeighborhood.class, Views.interval(output, interval), + Views.interval(input, interval), getOp(), shape); + } + else { + ops.run(MapNeighborhood.class, Views.interval(output, interval), + Views.interval(input, interval), getOp(), shape, oobFactory); + } } })); + } final FinalInterval finalCenter = center; @@ -176,8 +182,8 @@ public void run() { @Override public void run() { - ops.map(Views.interval(output, finalCenter), Views.interval(input, - finalCenter), getOp(), span); + ops.run(MapNeighborhoodNativeType.class, output, input, getOp(), span, + finalCenter); } })); @@ -199,23 +205,8 @@ public void run() { @Override public boolean conforms() { - if (!(getInput().numDimensions() > 0 || getInput().numDimensions() <= 3)) { - return false; - } - - /* all dimensions of the neighborhood have to be equal to be able to use - MapNeighborhoodNativeType */ - Neighborhood neighborhood = - shape.neighborhoodsRandomAccessible(getInput()).randomAccess().get(); - final long dimension0 = neighborhood.dimension(0); - - for (int i = 1; i < neighborhood.numDimensions(); ++i) { - if (dimension0 != neighborhood.dimension(i)) { - return false; - } - } - - return true; + return getInput().numDimensions() > 0 && getInput().numDimensions() <= 3 && + !shape.isSkippingCenter(); } // --- Cancelable methods --- diff --git a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java index 5aa92c0a45..fdadf0e3c2 100644 --- a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java +++ b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java @@ -7,6 +7,7 @@ import net.imagej.ops.AbstractOpTest; import net.imagej.ops.Op; import net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType; +import net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended; import net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType; import net.imglib2.algorithm.neighborhood.RectangleShape; import net.imglib2.img.Img; @@ -135,6 +136,28 @@ public void testMapNeighborhoodsArrayImage1D() { assertEquals("Index " + index + ": ", expected[index++], t.get()); } } + + /** + * TODO + * + * @see MapNeighborhoodNativeTypeExtended + */ + @Test + public void testMapNeighborhoodsArrayImageAlias() { + in = generateByteTestImg(true, 7); + out = generateByteTestImg(false, 7); + + final Op functional = + ops.op(MapNeighborhoodNativeTypeExtended.class, out, in, + new CountNeighbors(), new RectangleShape(1, false)); + functional.run(); + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index, 3, t.get()); + index ++; + } + } /** * Test if every neighborhood pixel of the 3D image was really accessed during From e102430669b06fa9eeef9b57dfc1b205cdfe8def Mon Sep 17 00:00:00 2001 From: squareys Date: Tue, 15 Sep 2015 11:26:10 +0200 Subject: [PATCH 10/14] Add test for MapNeighborhoodNativeTypeExtended Signed-off-by: squareys --- .../map/neighborhood/MapNeighborhoodTest.java | 62 ++++++++++++++++--- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java index fdadf0e3c2..aab407e36d 100644 --- a/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java +++ b/src/test/java/net/imagej/ops/map/neighborhood/MapNeighborhoodTest.java @@ -112,6 +112,29 @@ public void testMapNeighborhoodsArrayImage2D() { } } + /** + * Test if every neighborhood pixel of the 2D image was really accessed during + * the map operation. + * + * @see MapNeighborhoodNativeTypeExtended + */ + @Test + public void testMapNeighborhoodsArrayImageAlias2D() { + in = generateByteTestImg(true, 7, 7); + out = generateByteTestImg(false, 7, 7); + + final Op functional = + ops.op(MapNeighborhoodNativeTypeExtended.class, out, in, + new CountNeighbors(), new RectangleShape(1, false)); + functional.run(); + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index + ": ", 9, t.get()); + index++; + } + } + /** * Test if every neighborhood pixel of the 1D image was really accessed during * the map operation. @@ -128,22 +151,22 @@ public void testMapNeighborhoodsArrayImage1D() { new CountNeighborsWithAccess(), 1); functional.run(); - final byte[] expected = - new byte[] { 2, 3, 3, 3, 3, 3, 2 }; + final byte[] expected = new byte[] { 2, 3, 3, 3, 3, 3, 2 }; int index = 0; for (ByteType t : out) { assertEquals("Index " + index + ": ", expected[index++], t.get()); } } - + /** - * TODO + * Test if every neighborhood pixel of the 1D image was really accessed during + * the map operation. * * @see MapNeighborhoodNativeTypeExtended */ @Test - public void testMapNeighborhoodsArrayImageAlias() { + public void testMapNeighborhoodsArrayImageAlias1D() { in = generateByteTestImg(true, 7); out = generateByteTestImg(false, 7); @@ -154,8 +177,8 @@ public void testMapNeighborhoodsArrayImageAlias() { int index = 0; for (ByteType t : out) { - assertEquals("Index " + index, 3, t.get()); - index ++; + assertEquals("Index " + index + ": ", 3, t.get()); + index++; } } @@ -184,6 +207,29 @@ public void testMapNeighborhoodsArrayImage3D() { assertEquals("Index " + index + ": ", expected[index++], t.get()); } } + + /** + * Test if every neighborhood pixel of the 3D image was really accessed during + * the map operation. + * + * @see MapNeighborhoodNativeTypeExtended + */ + @Test + public void testMapNeighborhoodsArrayImageAlias3D() { + in = generateByteTestImg(true, 7, 7, 7); + out = generateByteTestImg(false, 7, 7, 7); + + final Op functional = + ops.op(MapNeighborhoodNativeTypeExtended.class, out, in, + new CountNeighbors(), new RectangleShape(1, false)); + functional.run(); + + int index = 0; + for (ByteType t : out) { + assertEquals("Index " + index + ": ", 27, t.get()); + index++; + } + } /** * Test if every neighborhood pixel of the 2D image was really accessed during @@ -210,6 +256,8 @@ public void testMapNeighborhoodsWithCenterAccessArrayImage2D() { assertEquals("Index " + index + ": ", expected[index++], t.get()); } } + + /** * Function which increments the output value for every pixel in the From e8a6a88c2f533518351d1c7a7dc03795fbc9d310 Mon Sep 17 00:00:00 2001 From: squareys Date: Tue, 15 Sep 2015 12:15:21 +0200 Subject: [PATCH 11/14] Format Code Signed-off-by: squareys --- .../array/MapNeighborhoodNativeTypeExtended.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java index a35911fc7b..08f8760afb 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java @@ -4,8 +4,8 @@ import java.util.ArrayList; import java.util.concurrent.Future; +import net.imagej.ops.ComputerOp; import net.imagej.ops.Contingent; -import net.imagej.ops.Op; import net.imagej.ops.OpService; import net.imagej.ops.Ops; import net.imagej.ops.map.AbstractMapComputer; @@ -36,7 +36,7 @@ * @see MapNeighborhoodWithCenterNativeType * @see MapNeighborhood */ -@Plugin(type = Op.class, name = Ops.Map.NAME, +@Plugin(type = net.imagej.ops.Op.class, name = Ops.Map.NAME, priority = Priority.LOW_PRIORITY + 10) public class MapNeighborhoodNativeTypeExtended, O extends NativeType> extends AbstractMapComputer, O, ArrayImg, ArrayImg> @@ -134,7 +134,8 @@ else if (numDimensions == 2) { intervals = new FinalInterval[] { /* front */ - new FinalInterval(new long[] { 0, 0, 0 }, new long[] { max0, max1, span }), + new FinalInterval(new long[] { 0, 0, 0 }, new long[] { max0, max1, + span }), /* back */ new FinalInterval(new long[] { 0, 0, dim2 - span }, new long[] { max0, max1, max2 }), @@ -148,8 +149,8 @@ else if (numDimensions == 2) { new FinalInterval(new long[] { 0, spanPlus1, spanPlus1 }, new long[] { span, maxSafe1, maxSafe2 }), /* right */ - new FinalInterval(new long[] { dim0 - span, spanPlus1, spanPlus1 }, new long[] { - max0, maxSafe1, maxSafe2 }) }; + new FinalInterval(new long[] { dim0 - span, spanPlus1, spanPlus1 }, + new long[] { max0, maxSafe1, maxSafe2 }) }; /* center */ center = new FinalInterval(new long[] { spanPlus1, spanPlus1, spanPlus1 }, From 5fe7185738973e6cfe16c24826af24ed62bead14 Mon Sep 17 00:00:00 2001 From: squareys Date: Tue, 15 Sep 2015 12:15:43 +0200 Subject: [PATCH 12/14] Make MapNeighborhoodNativeType useable with CenterAwareComputer Signed-off-by: squareys --- .../neighborhood/array/MapNeighborhoodNativeTypeExtended.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java index 08f8760afb..83105b6a97 100644 --- a/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java +++ b/src/main/java/net/imagej/ops/map/neighborhood/array/MapNeighborhoodNativeTypeExtended.java @@ -38,7 +38,7 @@ */ @Plugin(type = net.imagej.ops.Op.class, name = Ops.Map.NAME, priority = Priority.LOW_PRIORITY + 10) -public class MapNeighborhoodNativeTypeExtended, O extends NativeType> +public class MapNeighborhoodNativeTypeExtended, O extends NativeType, Op extends ComputerOp> extends AbstractMapComputer, O, ArrayImg, ArrayImg> implements Contingent, Cancelable { From 627aaaabd127cfadba401159c166fde36c6a79fa Mon Sep 17 00:00:00 2001 From: squareys Date: Tue, 15 Sep 2015 12:38:02 +0200 Subject: [PATCH 13/14] Add missing OpMethods Signed-off-by: squareys --- .../net/imagej/ops/AbstractOpEnvironment.java | 48 ++++++++++++------- .../java/net/imagej/ops/OpEnvironment.java | 42 +++++++++------- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java index 954f9d4e91..47df8ceb00 100644 --- a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java +++ b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java @@ -51,6 +51,7 @@ import net.imagej.ops.stats.StatsNamespace; import net.imagej.ops.thread.ThreadNamespace; import net.imagej.ops.threshold.ThresholdNamespace; +import net.imglib2.Interval; import net.imglib2.IterableInterval; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; @@ -512,53 +513,68 @@ public RandomAccessibleInterval map( @Override public , O extends NativeType> ArrayImg map( - final ArrayImg out, final ArrayImg in, - final CenterAwareComputerOp op, final Integer span) + ArrayImg out, ArrayImg in, ComputerOp, O> op, + RectangleShape shape) { @SuppressWarnings("unchecked") final ArrayImg result = (ArrayImg) run( - net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType.class, - out, in, op, span); + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class, + out, in, op, shape); return result; } @Override public , O extends NativeType> ArrayImg map( - final ArrayImg out, final ArrayImg in, - final ComputerOp, O> op, final Integer span) + ArrayImg out, ArrayImg in, ComputerOp, O> op, + RectangleShape shape, OutOfBoundsFactory oobFactory) { @SuppressWarnings("unchecked") final ArrayImg result = (ArrayImg) run( - net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class, + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class, + out, in, op, shape, oobFactory); + return result; + } + + @Override + public + , O extends NativeType> ArrayImg map( + final ArrayImg out, final ArrayImg in, + final CenterAwareComputerOp op, final int span) + { + @SuppressWarnings("unchecked") + final ArrayImg result = + (ArrayImg) run( + net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType.class, out, in, op, span); return result; } @Override public , O extends NativeType> ArrayImg map( - ArrayImg out, ArrayImg in, ComputerOp, O> op, - RectangleShape shape) + final ArrayImg out, final ArrayImg in, + final ComputerOp, O> op, final int span) { @SuppressWarnings("unchecked") final ArrayImg result = (ArrayImg) run( - net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class, - out, in, op, shape); + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class, + out, in, op, span); return result; } @Override - public , O extends NativeType> ArrayImg map( - ArrayImg out, ArrayImg in, ComputerOp, O> op, - RectangleShape shape, OutOfBoundsFactory oobFactory) + public , O extends NativeType> ArrayImg + map(final ArrayImg out, final ArrayImg in, + final ComputerOp, O> op, final int span, + final Interval interval) { @SuppressWarnings("unchecked") final ArrayImg result = (ArrayImg) run( - net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class, - out, in, op, shape, oobFactory); + net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class, + out, in, op, span, interval); return result; } diff --git a/src/main/java/net/imagej/ops/OpEnvironment.java b/src/main/java/net/imagej/ops/OpEnvironment.java index 2067e4c4fe..0d1dfd8628 100644 --- a/src/main/java/net/imagej/ops/OpEnvironment.java +++ b/src/main/java/net/imagej/ops/OpEnvironment.java @@ -48,6 +48,7 @@ import net.imagej.ops.stats.StatsNamespace; import net.imagej.ops.thread.ThreadNamespace; import net.imagej.ops.threshold.ThresholdNamespace; +import net.imglib2.Interval; import net.imglib2.IterableInterval; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; @@ -300,8 +301,8 @@ public interface OpEnvironment extends Contextual { /** Executes the "join" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.join.DefaultJoinComputerAndComputer.class) - C join(C out, A in, ComputerOp first, ComputerOp second, - BufferFactory bufferFactory); + C join(C out, A in, ComputerOp first, + ComputerOp second, BufferFactory bufferFactory); /** Executes the "join" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.join.DefaultJoinInplaceAndInplace.class) @@ -403,20 +404,6 @@ RandomAccessibleInterval map(RandomAccessibleInterval out, RandomAccessibleInterval in, CenterAwareComputerOp, O> op, Shape shape); - /** Executes the "map" operation on the given arguments. */ - @OpMethod( - op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType.class) - , O extends NativeType> ArrayImg map( - ArrayImg out, ArrayImg in, CenterAwareComputerOp op, - Integer span); - - /** Executes the "map" operation on the given arguments. */ - @OpMethod( - op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class) - , O extends NativeType> ArrayImg map( - ArrayImg out, ArrayImg in, ComputerOp, O> op, - Integer span); - /** Executes the "map" operation on the given arguments. */ @OpMethod( op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeTypeExtended.class) @@ -433,6 +420,29 @@ RandomAccessibleInterval map(RandomAccessibleInterval out, ArrayImg out, ArrayImg in, ComputerOp, O> op, RectangleShape shape, OutOfBoundsFactory oobFactory); + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodWithCenterNativeType.class) + public + , O extends NativeType> ArrayImg map( + final ArrayImg out, final ArrayImg in, + final CenterAwareComputerOp op, final int span); + + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class) + public , O extends NativeType> ArrayImg map( + final ArrayImg out, final ArrayImg in, + final ComputerOp, O> op, final int span); + + /** Executes the "map" operation on the given arguments. */ + @OpMethod( + op = net.imagej.ops.map.neighborhood.array.MapNeighborhoodNativeType.class) + public , O extends NativeType> ArrayImg + map(final ArrayImg out, final ArrayImg in, + final ComputerOp, O> op, final int span, + final Interval interval); + /** Executes the "map" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.map.MapIterableToIterable.class) Iterable map(Iterable out, Iterable in, ComputerOp op); From 989e5823a91a2e6db7db161ee01e53c052e7b3c8 Mon Sep 17 00:00:00 2001 From: squareys Date: Tue, 15 Sep 2015 12:39:00 +0200 Subject: [PATCH 14/14] Format OpEnvironment and AbstractOpEnvironment Signed-off-by: squareys --- .../net/imagej/ops/AbstractOpEnvironment.java | 35 ++++++++++--------- .../java/net/imagej/ops/OpEnvironment.java | 3 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java index 47df8ceb00..4c66977621 100644 --- a/src/main/java/net/imagej/ops/AbstractOpEnvironment.java +++ b/src/main/java/net/imagej/ops/AbstractOpEnvironment.java @@ -186,8 +186,9 @@ public , O extends RealType> O convert(final O out, { @SuppressWarnings("unchecked") final IterableInterval result = - (IterableInterval) run(net.imagej.ops.convert.ConvertIterableInterval.class, out, - in, pixConvert); + (IterableInterval) run( + net.imagej.ops.convert.ConvertIterableInterval.class, out, in, + pixConvert); return result; } @@ -228,7 +229,6 @@ public String help(final Namespace namespace) { return result; } - @Override public String help() { final String result = @@ -269,8 +269,8 @@ public Object join(final Object... args) { } @Override - public C join(final C out, final A in, final ComputerOp first, - final ComputerOp second) + public C join(final C out, final A in, + final ComputerOp first, final ComputerOp second) { @SuppressWarnings("unchecked") final C result = @@ -280,8 +280,9 @@ public C join(final C out, final A in, final ComputerOp first, } @Override - public C join(final C out, final A in, final ComputerOp first, - final ComputerOp second, final BufferFactory bufferFactory) + public C join(final C out, final A in, + final ComputerOp first, final ComputerOp second, + final BufferFactory bufferFactory) { @SuppressWarnings("unchecked") final C result = @@ -308,8 +309,8 @@ public A join(final A out, final A in, { @SuppressWarnings("unchecked") final A result = - (A) run(net.imagej.ops.join.DefaultJoinComputers.class, out, in, - ops, bufferFactory); + (A) run(net.imagej.ops.join.DefaultJoinComputers.class, out, in, ops, + bufferFactory); return result; } @@ -425,8 +426,7 @@ public > IterableInterval map( @SuppressWarnings("unchecked") final IterableInterval result = (IterableInterval) run( - net.imagej.ops.map.MapIterableIntervalToView.class, input, op, - type); + net.imagej.ops.map.MapIterableIntervalToView.class, input, op, type); return result; } @@ -494,7 +494,8 @@ public RandomAccessibleInterval map( @SuppressWarnings("unchecked") final RandomAccessibleInterval result = (RandomAccessibleInterval) run( - net.imagej.ops.map.neighborhood.MapNeighborhood.class, out, in, op, shape); + net.imagej.ops.map.neighborhood.MapNeighborhood.class, out, in, op, + shape); return result; } @@ -507,7 +508,8 @@ public RandomAccessibleInterval map( @SuppressWarnings("unchecked") final RandomAccessibleInterval result = (RandomAccessibleInterval) run( - net.imagej.ops.map.neighborhood.MapNeighborhoodWithCenter.class, out, in, func, shape); + net.imagej.ops.map.neighborhood.MapNeighborhoodWithCenter.class, out, + in, func, shape); return result; } @@ -538,10 +540,9 @@ public RandomAccessibleInterval map( } @Override - public - , O extends NativeType> ArrayImg map( - final ArrayImg out, final ArrayImg in, - final CenterAwareComputerOp op, final int span) + public , O extends NativeType> ArrayImg map( + final ArrayImg out, final ArrayImg in, + final CenterAwareComputerOp op, final int span) { @SuppressWarnings("unchecked") final ArrayImg result = diff --git a/src/main/java/net/imagej/ops/OpEnvironment.java b/src/main/java/net/imagej/ops/OpEnvironment.java index 0d1dfd8628..3c0eb9d54f 100644 --- a/src/main/java/net/imagej/ops/OpEnvironment.java +++ b/src/main/java/net/imagej/ops/OpEnvironment.java @@ -297,7 +297,8 @@ public interface OpEnvironment extends Contextual { /** Executes the "join" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.join.DefaultJoinComputerAndComputer.class) - C join(C out, A in, ComputerOp first, ComputerOp second); + C + join(C out, A in, ComputerOp first, ComputerOp second); /** Executes the "join" operation on the given arguments. */ @OpMethod(op = net.imagej.ops.join.DefaultJoinComputerAndComputer.class)