ImageJ Tutorials and Demo

Welcome to the ImageJ tutorial series. These notebooks offer a hands-on series of lessons for learning ImageJ.

Feedback is very welcome! Please share your ideas on the ImageJ Forum!

Advanced extensions

  1. Creating a custom service (coming later)
  2. Customizing module execution (coming later)
  3. Creating a SCIFIO plugin (coming later)

Installation for ImageJ in Jupyter notebooks

The first section is only necessary if you want to run ImageJ commands from Jupyter notebooks. In order to run the notebook, please install Anaconda from its website. Afterwards, please install the BeakerX kernel from the Anaconda command line:

conda install -c conda-forge ipywidgets beakerx

Find out more about BeakerX

If you are running from within the ImageJ/Fiji script editor, you don't need the first code snippet. It is to tell the notebook to download and install ImageJ from the remote repository.

In [1]:
%classpath config resolver imagej.public https://maven.imagej.net/content/groups/public
%%classpath add mvn
net.imagej imagej 2.0.0-rc-71
net.imagej imagej-notebook 0.7.1
Added new repo: imagej.public

Now that ImageJ functionality is available to the notebook, we create an ImageJ gateway.

Using ImageJ

In order to use ImageJ, you need a variable ij which offers you all the functionality. In ImageJs script editor, just add a line

#@ ImageJ ij

In Jupyter notebooks, you can call this:

In [6]:
ij = new net.imagej.ImageJ()
"ImageJ v${ij.getVersion()} is ready to go."
Out[6]:
ImageJ v2.0.0-rc-71 is ready to go.

For further details, see the Fundamentals of ImageJ notebook.

Load an image

You can open images from local files as well as remote URLs.

In [9]:
// image = ij.io().open("https://imagej.net/images/lymp.tif")
image = ij.io().open("C:/structure/data/lymp.tif")
Out[9]:

Compute histogram

In [10]:
histogram = ij.op().image().histogram(image)
Out[10]:
Histogram

A first example: Count cells

In [11]:
binaryImage = ij.op().threshold().huang(image)
Out[11]:
In [12]:
import net.imglib2.algorithm.labeling.ConnectedComponents;
ij.op().labeling().cca(image, ConnectedComponents.StructuringElement.EIGHT_CONNECTED);
Out[12]:
java.lang.IllegalArgumentException: Unsupported image type: net.imglib2.roi.labeling.LabelingType
	at net.imagej.notebook.image.RAIToHTMLConverter.lambda$convert$0(RAIToHTMLConverter.java:71)
	at net.imagej.notebook.DefaultNotebookService.lambda$initialize$3(DefaultNotebookService.java:107)
	at net.imagej.notebook.BeakerX$1.display(BeakerX.java:64)
	at jupyter.Displayers.display(Displayers.java:62)
	at com.twosigma.beakerx.MIMEContainerFactory.createMIMEContainersFromObject(MIMEContainerFactory.java:84)
	at com.twosigma.beakerx.MIMEContainerFactory.createMIMEContainers(MIMEContainerFactory.java:46)
	at com.twosigma.beakerx.kernel.msg.MessageCreator.createFinishResult(MessageCreator.java:265)
	at com.twosigma.beakerx.kernel.msg.MessageCreator.createFinish(MessageCreator.java:181)
	at com.twosigma.beakerx.kernel.msg.MessageCreator.createMessage(MessageCreator.java:172)
	at com.twosigma.beakerx.kernel.threads.ExecutionResultSender.update(ExecutionResultSender.java:45)
	at com.twosigma.beakerx.jvm.object.SimpleEvaluationObject.finished(SimpleEvaluationObject.java:72)
	at com.twosigma.beakerx.kernel.CodeFrame.handleResult(CodeFrame.java:40)
	at com.twosigma.beakerx.kernel.PlainCode.executeLastFrame(PlainCode.java:50)
	at com.twosigma.beakerx.kernel.Code.execute(Code.java:90)
	at com.twosigma.beakerx.kernel.handler.ExecuteRequestHandler.handleMsg(ExecuteRequestHandler.java:63)
	at com.twosigma.beakerx.kernel.handler.ExecuteRequestHandler.handle(ExecuteRequestHandler.java:51)
	at com.twosigma.beakerx.kernel.handler.ExecuteRequestHandler.handle(ExecuteRequestHandler.java:39)
	at com.twosigma.beakerx.socket.KernelSocketsZMQ.handleShell(KernelSocketsZMQ.java:195)
	at com.twosigma.beakerx.socket.KernelSocketsZMQ.run(KernelSocketsZMQ.java:170)

Type conversion

In [7]:
eyes32 = ij.op().convert().float32(eyes)
Out[7]:
In [8]:
eyes.firstElement().getClass().getName()
Out[8]:
net.imglib2.type.numeric.integer.UnsignedByteType
In [9]:
eyes32.firstElement().getClass().getName()
Out[9]:
net.imglib2.type.numeric.real.FloatType

Median filter with circular neighborhood

In [10]:
import net.imglib2.algorithm.neighborhood.HyperSphereShape
median = ij.op().run("create.img", eyes32)
neighborhood = new HyperSphereShape(4)
ij.op().run("filter.median", median, eyes32, neighborhood)
Out[10]:

Difference of Gaussians formula

In [11]:
dogFormula = "gauss(image, sigma1) - gauss(image, sigma2)"
dog = ij.op().eval(dogFormula, [
  "image": eyes32,
  "sigma1": [20, 20],
  "sigma2": [4, 4]
])
Out[11]:

Grayscale morphology operators

In [12]:
topHat = ij.op().morphology().topHat(eyes, [neighborhood])
Out[12]:
In [13]:
blackTopHat = ij.op().morphology().blackTopHat(eyes, [neighborhood])
Out[13]:

Display multiple images at once

In [14]:
ij.notebook().display(["median":median, "topHat":topHat, "blackTopHat":blackTopHat])
Out[14]:
median
topHat
blackTopHat
In [15]:
ij.notebook().display([["median":median, "topHat":topHat, "blackTopHat":blackTopHat]])
Out[15]:
mediantopHatblackTopHat

Fourier transform with lowpass filter

Define a lowpass filtering function, operating in the Fourier domain:

In [16]:
import net.imglib2.util.Util

lowpass = { fft, radius ->
  // Declare an array to hold the current position of the cursor.
  pos = new long[fft.numDimensions()]

  // Define origin as 0,0.
  long[] origin = [0, 0]

  // Define a 2nd 'origin' at bottom left of image.
  // This is a bit of a hack. We want to draw a circle around the origin,
  // since the origin is at 0,0 - the circle will 'reflect' to the bottom.
  long[] origin2 = [0, fft.dimension(1)]

  // Loop through all pixels.
  cursor = fft.localizingCursor()
  while (cursor.hasNext()) {
    cursor.fwd()
    cursor.localize(pos)

    // Calculate distance from 0,0 and bottom left corner
    // (so we can form the reflected semi-circle).
    dist = Util.distance(origin, pos)
    dist2 = Util.distance(origin2, pos)

    // If distance is above radius (cutoff frequency) set value of FFT to zero.
    if (dist > radius && dist2 > radius)
      cursor.get().setZero()
  }
}
Out[16]:
[email protected]

Perform a fast Fourier transform (FFT) on the image, run the lowpass filter, then invert the FFT:

In [17]:
import net.imglib2.type.numeric.real.FloatType

// Perform fft of the input.
fft = ij.op().filter().fft(image)

// Filter it.
lowpass(fft, radius=10)

// Reverse the FFT.
inverse = ij.op().run("create.img", image, new FloatType())
ij.op().filter().ifft(inverse, fft)

// Display the result.
ij.notebook().display([["image":image, "lowpass":inverse]])
Out[17]:
imagelowpass