Skip to content

Commit afeb0b5

Browse files
gselzerhinerm
authored andcommitted
Write Parllel Ops tutorial
1 parent f9b9333 commit afeb0b5

2 files changed

Lines changed: 111 additions & 0 deletions

File tree

imagej/imagej-ops2-tutorial/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363

6464
provides org.scijava.ops.spi.OpCollection with
6565
net.imagej.ops2.tutorial.OpAdaptation,
66+
net.imagej.ops2.tutorial.OpParallelization,
6667
net.imagej.ops2.tutorial.OpReduction,
6768
net.imagej.ops2.tutorial.OpSimplification,
6869
net.imagej.ops2.tutorial.ReportingProgress,
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
2+
package net.imagej.ops2.tutorial;
3+
4+
import java.util.stream.Collectors;
5+
import java.util.stream.IntStream;
6+
7+
import org.scijava.function.Computers;
8+
import org.scijava.ops.api.OpEnvironment;
9+
import org.scijava.ops.engine.DefaultOpEnvironment;
10+
import org.scijava.ops.spi.OpCollection;
11+
import org.scijava.ops.spi.OpMethod;
12+
13+
import net.imglib2.Interval;
14+
import net.imglib2.algorithm.neighborhood.Neighborhood;
15+
import net.imglib2.algorithm.neighborhood.RectangleShape;
16+
import net.imglib2.algorithm.neighborhood.Shape;
17+
import net.imglib2.img.Img;
18+
import net.imglib2.img.array.ArrayImgs;
19+
import net.imglib2.loops.IntervalChunks;
20+
import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory;
21+
import net.imglib2.parallel.Parallelization;
22+
import net.imglib2.type.numeric.integer.UnsignedByteType;
23+
import net.imglib2.view.Views;
24+
25+
/**
26+
* SciJava Ops includes a mechanism for automatically introducing concurrency to
27+
* Ops.
28+
*
29+
* Developers can utilize this mechanism by writing their Ops on the smallest
30+
* element of the computation, be that a single pixel, or a {@link Neighborhood}.
31+
* SciJava Ops will then "lift" these Ops, creating parallelized Ops that run
32+
* on an entire {@link net.imglib2.RandomAccessibleInterval}
33+
*
34+
* This tutorial showcases these lifting mechanisms.
35+
*
36+
* @author Gabriel Selzer
37+
*/
38+
public class OpParallelization implements OpCollection {
39+
40+
/**
41+
* This Op, which is really just a computation on a single pixel, lets the
42+
* framework assume the burden of parallelization
43+
*
44+
* @param input the input pixel
45+
* @param output the preallocated output pixel
46+
*/
47+
@OpMethod(names = "tutorial.invertPerPixel", type = Computers.Arity1.class)
48+
public static void invertOp(UnsignedByteType input, UnsignedByteType output) {
49+
output.set(255 - input.get());
50+
}
51+
52+
/**
53+
* This Op, which computes some algorithm over a neighborhood, also lets the
54+
* framework assume the burden of parallelization
55+
*
56+
* @param input the input pixel
57+
* @param output the preallocated output pixel
58+
*/
59+
@OpMethod(names = "tutorial.neighborhoodAverage",
60+
type = Computers.Arity1.class)
61+
public static void averageNeighborhood(Neighborhood<UnsignedByteType> input,
62+
UnsignedByteType output)
63+
{
64+
long tmp = 0;
65+
var cursor = input.cursor();
66+
while (cursor.hasNext()) {
67+
tmp += cursor.next().getIntegerLong();
68+
}
69+
output.setInteger(tmp / input.size());
70+
}
71+
72+
public static void main(String... args) {
73+
OpEnvironment ops = new DefaultOpEnvironment();
74+
75+
// First, we show parallelization at work for our per-pixel Op.
76+
// SciJava Ops understands how to apply that Op to each pixel of the input
77+
// image
78+
79+
// Fill an input image with a value
80+
var fillValue = new UnsignedByteType(5);
81+
var inImg = ArrayImgs.unsignedBytes(10, 10);
82+
ops.op("image.fill").arity1().input(fillValue).output(inImg).compute();
83+
// Run the Op
84+
var outImg = ArrayImgs.unsignedBytes(10, 10);
85+
ops.op("tutorial.invertPerPixel").arity1().input(inImg).output(outImg)
86+
.compute();
87+
// Get the original value, and the inverted value
88+
var original = inImg.firstElement().get();
89+
var inverted = outImg.firstElement().get();
90+
System.out.println("Original image was filled with value " + original +
91+
", and the inverted image is filled with value (255 - " + original +
92+
") = " + inverted);
93+
94+
// Now, we show parallelization at work for our Parallelization Op.
95+
// For this example, we use a radius-1 rectangle; in other words, the
96+
// neighborhood
97+
// for a given pixel includes all of its immediate neighbors (including
98+
// diagonal)
99+
var shape = new RectangleShape(1, false);
100+
ops.op("tutorial.neighborhoodAverage").arity2().input(inImg, shape)
101+
.output(outImg).compute();
102+
// Get the original value, and the radius-1 neighborhood value
103+
original = inImg.firstElement().get();
104+
var mean = outImg.firstElement().get();
105+
System.out.println("Original image was filled with value " + original +
106+
", and the radius-1 mean at the corner is (4 * " + original + " / 9) = " +
107+
mean);
108+
}
109+
110+
}

0 commit comments

Comments
 (0)