diff --git a/howtos/pom.xml b/howtos/pom.xml
index 40c2bbcb..e9aba578 100644
--- a/howtos/pom.xml
+++ b/howtos/pom.xml
@@ -8,7 +8,7 @@
org.scijava
pom-scijava
- 26.0.0
+ 28.0.0
@@ -71,6 +71,7 @@
unlicense
N/A
ImageJ software for multidimensional image processing and analysis.
+ 5.9.0
diff --git a/howtos/src/main/java/howto/images/processing/loopbuilder/HandleInChunks.java b/howtos/src/main/java/howto/images/processing/loopbuilder/HandleInChunks.java
new file mode 100644
index 00000000..a52e6226
--- /dev/null
+++ b/howtos/src/main/java/howto/images/processing/loopbuilder/HandleInChunks.java
@@ -0,0 +1,60 @@
+/*
+ * To the extent possible under law, the ImageJ developers have waived
+ * all copyright and related or neighboring rights to this tutorial code.
+ *
+ * See the Unlicense for details:
+ * https://unlicense.org/
+ */
+
+package howto.images.processing.loopbuilder;
+
+import net.imagej.ImageJ;
+import net.imglib2.img.Img;
+import net.imglib2.loops.LoopBuilder;
+import net.imglib2.type.numeric.real.DoubleType;
+
+import java.util.List;
+
+/**
+ * How to use the LoopBuilder to process an image in chunks
+ *
+ * @author Matthias Arzt
+ * @author Deborah Schmidt
+ */
+public class HandleInChunks {
+
+ public static void run() {
+
+ ImageJ ij = new ImageJ();
+
+ // create image
+ Img image = ij.op().create().img(new long[]{10, 10});
+ for (int x = 0; x < 10; x++) {
+ for (int y = 0; y < 10; y++) {
+ image.getAt(x, y).set(x+y);
+ }
+ }
+
+ List listOfSums = LoopBuilder.setImages( image ).multiThreaded().forEachChunk(
+ chunk -> {
+ DoubleType sum = new DoubleType();
+ chunk.forEachPixel( pixel -> {
+ sum.add(new DoubleType(pixel.getRealDouble()));
+ });
+ return sum;
+ }
+ );
+
+ DoubleType totalSum = new DoubleType();
+ listOfSums.forEach(totalSum::add);
+
+ System.out.println(totalSum);
+
+ ij.dispose();
+ }
+
+ public static void main(String...args) {
+ run();
+ }
+
+}
diff --git a/howtos/src/main/java/howto/images/processing/loopbuilder/LoopWithPosition.java b/howtos/src/main/java/howto/images/processing/loopbuilder/LoopWithPosition.java
new file mode 100644
index 00000000..db596fc7
--- /dev/null
+++ b/howtos/src/main/java/howto/images/processing/loopbuilder/LoopWithPosition.java
@@ -0,0 +1,47 @@
+/*
+ * To the extent possible under law, the ImageJ developers have waived
+ * all copyright and related or neighboring rights to this tutorial code.
+ *
+ * See the Unlicense for details:
+ * https://unlicense.org/
+ */
+
+package howto.images.processing.loopbuilder;
+
+import net.imagej.ImageJ;
+import net.imglib2.img.Img;
+import net.imglib2.loops.LoopBuilder;
+import net.imglib2.type.numeric.real.DoubleType;
+import net.imglib2.util.Intervals;
+
+/**
+ * How to use the LoopBuilder while accessing the position of a pixel
+ *
+ * @author Matthias Arzt
+ * @author Deborah Schmidt
+ */
+public class LoopWithPosition {
+
+ public static void run() {
+
+ ImageJ ij = new ImageJ();
+
+ Img image = ij.op().create().img(new long[]{50, 60});
+
+ LoopBuilder.setImages( Intervals.positions( image ), image ).forEachPixel(
+ ( position, pixel ) -> {
+ int x = position.getIntPosition( 0 );
+ int y = position.getIntPosition( 1 );
+ pixel.set( x * x + y * y );
+ }
+ );
+
+ ij.ui().show(image);
+
+ }
+
+ public static void main(String...args) {
+ run();
+ }
+
+}
diff --git a/howtos/src/main/java/howto/images/processing/loopbuilder/Multithreading.java b/howtos/src/main/java/howto/images/processing/loopbuilder/Multithreading.java
new file mode 100644
index 00000000..053ce02a
--- /dev/null
+++ b/howtos/src/main/java/howto/images/processing/loopbuilder/Multithreading.java
@@ -0,0 +1,48 @@
+/*
+ * To the extent possible under law, the ImageJ developers have waived
+ * all copyright and related or neighboring rights to this tutorial code.
+ *
+ * See the Unlicense for details:
+ * https://unlicense.org/
+ */
+
+package howto.images.processing.loopbuilder;
+
+import net.imagej.ImageJ;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.loops.LoopBuilder;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.real.DoubleType;
+
+import java.io.IOException;
+
+/**
+ * How to use the LoopBuilder running on multiple threads
+ *
+ * @author Matthias Arzt
+ * @author Deborah Schmidt
+ */
+public class Multithreading {
+
+ public static > void run() throws IOException {
+
+ ImageJ ij = new ImageJ();
+
+ // load example image
+ RandomAccessibleInterval source = (Img) ij.io().open(Object.class.getResource("/blobs.png").getPath());
+
+ // create result image
+ Img target = ij.op().create().img(source, new DoubleType());
+
+ LoopBuilder.setImages( source, target ).multiThreaded().forEachPixel( ( s, t ) -> t.set( s.getRealDouble() ) );
+
+ ij.ui().show(target);
+
+ }
+
+ public static void main(String...args) throws IOException {
+ run();
+ }
+
+}
diff --git a/howtos/src/main/java/howto/images/processing/loopbuilder/ProcessMultipleImages.java b/howtos/src/main/java/howto/images/processing/loopbuilder/ProcessMultipleImages.java
new file mode 100644
index 00000000..49bd9e1e
--- /dev/null
+++ b/howtos/src/main/java/howto/images/processing/loopbuilder/ProcessMultipleImages.java
@@ -0,0 +1,54 @@
+/*
+ * To the extent possible under law, the ImageJ developers have waived
+ * all copyright and related or neighboring rights to this tutorial code.
+ *
+ * See the Unlicense for details:
+ * https://unlicense.org/
+ */
+
+package howto.images.processing.loopbuilder;
+
+import net.imagej.ImageJ;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.loops.LoopBuilder;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.real.DoubleType;
+
+import java.io.IOException;
+
+/**
+ * How to use the LoopBuilder for processing multiple images together
+ *
+ * @author Matthias Arzt
+ * @author Deborah Schmidt
+ */
+public class ProcessMultipleImages {
+
+ public static & NativeType> void run() throws IOException {
+
+ ImageJ ij = new ImageJ();
+
+ // load example image to imageA
+ Img imageA = (Img) ij.io().open(Object.class.getResource("/blobs.png").getPath());
+ // set imageB to mirrored view of ImageA
+ RandomAccessibleInterval imageB = ij.op().transform().invertAxisView(imageA, 0);
+ // create result image
+ Img sum = ij.op().create().img(imageA, new DoubleType());
+
+ LoopBuilder.setImages(imageA, imageB, sum).forEachPixel(
+ (a, b, s) -> {
+ s.setReal(a.getRealDouble() + b.getRealDouble());
+ }
+ );
+
+ ij.ui().show(sum);
+
+ }
+
+ public static void main(String...args) throws IOException {
+ run();
+ }
+
+}