This notebooks introduces different image types and how they can be processed with CLIJ.
Let’s start by cleaaning up and opening an example image. For this, we use ImageJ-functions:
// clean up first run("Close All"); run("Clear Results"); // open the T1 heade example, a 3D MRI image open("http://imagej.nih.gov/ij/images/blobs.gif"); run("Invert LUT");
We now initialize the GPU and push the image as explained in the basics of clij tutorial.
run("CLIJ2 Macro Extensions", "cl_device="); Ext.CLIJ2_clear(); // push image to GPU memory blobs = getTitle(); Ext.CLIJ2_push(blobs);
Images can be filtered. Filters typically result in another image. We demonstrate that using a local median filter. As pixel neighborhood, we use “Box” which is also known as the 8-connected, or Moore neighborhood. Alternatively, the diamond-neighborhood coul be used, which is also known as the 4-connected, or von Neumann neighborhood.
radius = 3; Ext.CLIJ2_median2DBox(blobs, denoised_blobs, radius, radius); // show result Ext.CLIJ2_pull(denoised_blobs);
Operations which lead from any kind of image to binary images, binarze the given data. A binary images, or mask, has typically two values: 0 and 1. A common description of these two numbers is that 1 represents objects and 0 represents background. In CLIJ you can binarze images using mathematical operation such as comparison of pixels with a constant:
// compare if pixels are qual than a given value: value = 72; Ext.CLIJ2_equalConstant(blobs, binary, value); Ext.CLIJ2_pull(binary);
Note that we overwrite the results of the former operation when writing to the same “binary” image again using a different operation:
// compare if pixels are larger than a given value: value = 100; Ext.CLIJ2_greaterConstant(blobs, binary, value); Ext.CLIJ2_pull(binary);
In order eliminate the need for specifying such a threshold value manually, automatic thresholding algorithms have been developed, for example Otsu’s method:
Ext.CLIJ2_thresholdOtsu(blobs, binary); Ext.CLIJ2_pull(binary);
Operations which result in images where objects are numbered, are labeling the image data. One common operation for this is called connected component labeling. It takes a binary image as input:
Ext.CLIJ2_connectedComponentsLabelingBox(binary, labeled_blobs); Ext.CLIJ2_pull(labeled_blobs); // use a special [lookup-table](https://en.wikipedia.org/wiki/Lookup_table#Lookup_tables_in_image_processing) to visualize it: run("glasbey_on_dark");
There are more operations for labeling images, for example using a Voronoi diagram for separting the space between the white binary objects:
Ext.CLIJ2_voronoiLabeling(binary, labeled_blobs); Ext.CLIJ2_pull(labeled_blobs); run("glasbey_on_dark");
A shortcut for skipping filtering, thresholding, including a seeded watershed and labeling allows to go from an image to a label image directly. The method called Voronoi-Otsu-Labeling is explained in more detail here.
sigma_spot_finder = 4; sigma_outline_finder = 2; Ext.CLIJx_voronoiOtsuLabeling(blobs, labeled_blobs, sigma_spot_finder, sigma_outline_finder); Ext.CLIJ2_pull(labeled_blobs); run("glasbey_on_dark");
For visualization of quantitative measurements, parametric images can be used. Their pixel values represent a measurment that was taken from the labeled objects:
Ext.CLIJx_labelPixelCountMap(labeled_blobs, pixel_count_map); Ext.CLIJ2_pull(pixel_count_map); // use a different look-up table for visualization run("Green Fire Blue");
When working with parametric images, we should use ImageJ’s functionality to add a calibration bar and a scale bar:
run("Calibration Bar...", "location=[Upper Right] fill=White label=Black number=5 decimal=0 font=12 zoom=1"); run("Scale Bar...", "width=100 height=4 font=14 color=White background=None location=[Lower Left] bold overlay");