CLIJ2

Logo

GPU accelerated image processing for everyone

CLIJ2 home

Basics of image processing with CLIJ

This notebooks introduces how images can be processed with CLIJ.

Let’s start by cleaaning up and opening an example dataset. 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/t1-head.zip");

t1-head.tif

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
stack = getTitle();
Ext.CLIJ2_push(stack);

Images and image stacks

The image we loaded and pushed to the GPU is a 3D image, which can also be called an image stack. CLIJ supports 2D and 3D images only. Time lapses and multi-channel data need to be processed timepoint-by-timepoint and channel by channel.

We can find out how large our current image is by measuring its dimensions and writing them to the results table:

Ext.CLIJ2_getDimensions(stack, width, height, number_of_slices);
setResult("Width", 0, width);
setResult("Height", 0, height);
setResult("Number of slices", 0, number_of_slices);
WidthHeightNumber of slices
256256129

If you want to work with a single slice of such an image, you can retrieve it by copying it out of the stack. You need to provide a slice number, which counts 0-based. Thus, the first slice has index 0:

// copy a given slice
slice_index = 50;
Ext.CLIJ2_copySlice(stack, slice, slice_index);
// show the slice
Ext.CLIJ2_pull(slice);

CLIJ2_copySlice_result88

Alternatively, you can use projections to reduce a 3D image to a 2D image. This might makes sense for better visualization depending on the data:

// create projections
Ext.CLIJ2_maximumZProjection(stack, max_z_projection);
Ext.CLIJ2_meanXProjection(stack, mean_x_projection);
// show projections
Ext.CLIJ2_pull(max_z_projection);
Ext.CLIJ2_pull(mean_x_projection);

CLIJ2_maximumZProjection_result89 CLIJ2_meanXProjection_result90

Processing images in 2D and 3D

When processing images, you call a function and hand over at least two images: the input image and an output image. If the output image doesn’t exist yet, it will be created. If the output image exists already, it will be overwritten.

// apply a Gaussian blur filter
sigma = 5;
Ext.CLIJ2_gaussianBlur2D(slice, blurred, sigma, sigma);
// show result
Ext.CLIJ2_pull(blurred);

CLIJ2_gaussianBlur2D_result91

Note: If the output image exists already but has the wrong size, its size will not be changed. We can demonstrate that by creating an image in advance. Note: The size of the image may be misleading when viewing this example in the browser.

width = 150;
height = 150;
bit_depth = 32;
Ext.CLIJ2_create2D(to_small_image, width, height, bit_depth);
Ext.CLIJ2_gaussianBlur2D(slice, to_small_image, sigma, sigma);
// show result
Ext.CLIJ2_pull(to_small_image);

CLIJ2_create2D_result92

Furthermore, when working with some operations, e.g. the Gaussian blur, two versions exist: a 2D filter and a 3D filter. 2D filters cannot be applied to 3D images and vise versa. If you want to apply a filter slice by slice to a 3D image, set the radius or sigma parameter in z to 0:

sigma_z = 0;
Ext.CLIJ2_gaussianBlur3D(stack, blurred_stack, sigma, sigma, sigma_z);

Furthermore, there are operations which can be applied in 2D and 3D. Those don’t have either in their name. For example thresholding operations are dimensionality-agnostic:

Ext.CLIJ2_thresholdOtsu(slice, binary_slice);
Ext.CLIJ2_thresholdOtsu(stack, binary_stack);
// show binary masks
Ext.CLIJ2_pull(binary_slice);
Ext.CLIJ2_pull(binary_stack);

CLIJ2_thresholdOtsu_result94 CLIJ2_thresholdOtsu_result95