<jupyter_start><jupyter_text>N-dimensional image processingThis tutorial covers:* How to access and manipulate image sample values directly using [ImgLib2](https://imagej.net/ImgLib2)'s primary image structures.* How to perform image processing operations such as convolution, deconvolution and Fourier transforms.* How to work with non-rectangular regions of interest (ROIs) and do computational geometry.* How to compute image features and use them with machine learning algorithms.<jupyter_code>#@ImageJ ij

// Behind a firewall? Configure your proxy settings here.
//System.setProperty("http.proxyHost","myproxy.domain")
//System.setProperty("http.proxyPort","8080")

"ImageJ is ready to go."<jupyter_output><empty_output><jupyter_text>Image samples Images in ImageJ are backed by data structures from the [ImgLib2](https://imagej.net/ImgLib2) library. There are several important interfaces, but the two most crucial to understand initially are `IterableInterval` and `RandomAccessibleInterval`.As you can infer from their names, both of them are `Interval`s, which means finite, discrete point samplings in$\mathbb{Z}^{n}$bounded in each dimension. For example, a `uint8` image with dimensions $1024 \times 768$ is an interval in $\mathbb{Z}^{2}$ bounded in X (the first dimension) by $[0, 1023]$ and bounded in Y (the second dimension) by $[0, 767]$, with each integer coordinate inside the interval possessing some value $v \in \mathbb{Z} : 0 \leq v \leq 255$.* An `IterableInterval` is an image which can be [_iterated_](https://en.wikipedia.org/wiki/IterationComputing) in some order. That is, you can loop over its samples, although the _iteration order_ may vary depending on the type of image—that is, you cannot rely on a particular sample order _a priori_. The good news is that an `IterableInterval` _does_ know its dimensional position at each iteration. An `IterableInterval` is essentially a [stream](https://en.wikipedia.org/wiki/Stream_(computing)).* A `RandomAccessibleInterval` is an image which can be _inspected_ at will at arbitrary positions within the interval. In other words, it provides [_random access_](https://en.wikipedia.org/wiki/Random_access) to the image samples.If you are familiar with the `java.io` package of the Java standard library, `IterableInterval` is to `java.io.InputStream` as `RandomAccessibleInterval` is to `java.io.RandomAccessFile`.Let's dive into the API for each of these types of images!  Iterating images Here is a demonstration of image iteration:<jupyter_code>import net.imglib2.IterableInterval

// Create a tiny image.
image = ij.op().run("create.img", [5, 3])
println("The image is a " + image.getClass().getName())
println("image instanceof IterableInterval? " + (image instanceof IterableInterval))
println("Each sample is a " + image.firstElement().getClass().getName())

// Populate it with a diagonal gradient.
ij.op().image().equation(image, "p[0]+p[1]")

// Iterate over the image samples!
print("Sample values =")
for (v in image)
  print(" " + v)
println()<jupyter_output>The image is a net.imglib2.img.array.ArrayImg
image instanceof IterableInterval? true
Each sample is a net.imglib2.type.numeric.real.DoubleType
Sample values = 0.0 1.0 2.0 3.0 4.0 1.0 2.0 3.0 4.0 5.0 2.0 3.0 4.0 5.0 6.0<jupyter_text>The actual type of the created image object is `ArrayImg`, which is an _image container_ backed by one big array—in this case, a `double[]` because the samples are of type `DoubleType`.More generally: an `Img` is an object which is both an `IterableInterval` and a `RandomAccessibleInterval`. Other kinds of image containers include `PlanarImg` (one array per 2D slice) and `CellImg` (one array per N-dimensional block).You might be wondering: what if I need to know the dimensional position during iteration? The solution is to use a _cursor_:<jupyter_code>print("Samples by position:")
c = image.localizingCursor()
while (c.hasNext()) {
  v = c.next()
  xPos = c.getLongPosition(0)
  yPos = c.getLongPosition(1)
  if (xPos == 0) println()
  print("\t(" + xPos + ", " + yPos + ") = " + v)
}<jupyter_output>Samples by position:
	(0, 0) = 0.0	(1, 0) = 1.0	(2, 0) = 2.0	(3, 0) = 3.0	(4, 0) = 4.0
	(0, 1) = 1.0	(1, 1) = 2.0	(2, 1) = 3.0	(3, 1) = 4.0	(4, 1) = 5.0<jupyter_text>Each cursor is a pointer into the image somewhere, which knows its position. It is possible to run multiple cursors over an image simultaneously.Note that for performance, we use a _localizing cursor_ above by calling `localizingCursor()`, because we knew we would query the position every time. If we were going to query the position only rarely, `cursor()` would be better—a vanilla cursor still knows its position, but does less bookkeeping and hence is faster to iterate in cases where you don't query very often.  Iteration orders From the positions above, we see that the iteration order here happens to be nice and organized, with X moving fastest, followed by Y. This so-called _flat iteration order_ is what you get with `ArrayImg`, but may differ with other image containers. Here is an example of how a _cell image_ with $2 \times 2 \times 2$ blocks differs from an _array image_ of the same size:<jupyter_code>// Create an array image and a cell (2x2x2) image.
import net.imglib2.img.array.ArrayImgs
import net.imglib2.img.cell.CellImgFactory
long[] dims = [4, 2, 2]
arrayImg = ArrayImgs.unsignedBytes(dims)
cellImg = new CellImgFactory(2).create(dims, arrayImg.firstElement())

def printPositions(ii, width) {
  c = ii.localizingCursor()
  col = 0
  while (c.hasNext()) {
    v = c.next()
    xPos = c.getLongPosition(0)
    yPos = c.getLongPosition(1)
    zPos = c.getLongPosition(2)
    print("\t(" + xPos + ", " + yPos + ", " + zPos + ")")
    if (++col == width) { col = 0;  println() }
  }
  println()
}

println()
println("Array image iteration order =")
printPositions(arrayImg, 4)

println("Cell image iteration order =")
printPositions(cellImg, 4)<jupyter_output>(0, 2) = 2.0	(1, 2) = 3.0	(2, 2) = 4.0	(3, 2) = 5.0	(4, 2) = 6.0
Array image iteration order =
	(0, 0, 0)	(1, 0, 0)	(2, 0, 0)	(3, 0, 0)
	(0, 1, 0)	(1, 1, 0)	(2, 1, 0)	(3, 1, 0)
	(0, 0, 1)	(1, 0, 1)	(2, 0, 1)	(3, 0, 1)
	(0, 1, 1)	(1, 1, 1)	(2, 1, 1)	(3, 1, 1)

Cell image iteration order =
	(0, 0, 0)	(1, 0, 0)	(0, 1, 0)	(1, 1, 0)
	(0, 0, 1)	(1, 0, 1)	(0, 1, 1)	(1, 1, 1)
	(2, 0, 0)	(3, 0, 0)	(2, 1, 0)	(3, 1, 0)
	(2, 0, 1)	(3, 0, 1)	(2, 1, 1)	(3, 1, 1)<jupyter_text>Random Access Images  Accessing image samples directly Sometimes you need to access samples in an order other than the natural one. This is possible as long as the image implements the `RandomAccessible` interface.By Using RandomAccessible, we can get access to any pixel of the image in any order.Here is an example of using randomaccess method.<jupyter_code>import net.imglib2.RandomAccessibleInterval
import net.imglib2.img.array.ArrayImgs
import net.imglib2.img.cell.CellImgFactory
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.type.numeric.real.DoubleType;

// create array image and cell image
long[] dims = [128,96]
arrayImg = ArrayImgs.unsignedBytes(dims);
cellImg = new CellImgFactory(1).create(dims, arrayImg.firstElement())

// is the image RandomAccessible
println("Array image instanceof RandomAccessible? " + (arrayImg instanceof RandomAccessibleInterval))
println("Cell image instanceof RandomAccessible? " + (cellImg instanceof RandomAccessibleInterval))

// start drawing
def drawimage(image){
    ra = image.randomAccess()
    ra.setPosition(15,0)
    for (y in 15..45) {
        ra.setPosition(y, 1)
        UnsignedByteType t = ra.get()
        t.set(255)
    }


    ra.setPosition(15,1)
    for (x in 0..cellImg.dimension(0) - 1){
        ra.setPosition(x, 0)
        UnsignedByteType t =  ra.get()
        t.set(255)
    }

    ra.setPosition(112, 0)
    for (y in 15..45) {
        ra.setPosition(y, 1)
        UnsignedByteType t = ra.get()
        t.set(255)
    }

    ra.setPosition(80, 1)
    for (x in 57..71){
        ra.setPosition(x, 0)
        UnsignedByteType t =  ra.get()
        t.set(255)
    }
}

drawimage(arrayImg)
drawimage(cellImg)
[arrayImg,cellImg]<jupyter_output>Array image instanceof RandomAccessible? true
Cell image instanceof RandomAccessible? true
StarcoderdataJupyterStructuredCleanDedup