Simple CLIJ macro not returning image with same dimensions

Hi Roooobert

I am trying to simply do a gaussian blur with CLIJ (2D + 2Ch + time) and modified your simple macro, but the output returns only a single 2 color image… I tried with bioformats importer and using the simple "open(path), and both won’t work.
any idea what I am doing wrong?

Also, any small CLIJ macro example for batch processing? did not find on the clij github page… just to have an idea how to handle the GPU pushing/pulling in batch

run("Close All");

// open dataset
open("D:/SCIENCE/Microscopy/0_Airy/DO15_endoTRF1 live_siNUMA/20190422_cl7_NuMA_MAX/MAXProj/20190422_CL7_siCTRL_Pos02_MAX.tif");
getDimensions(width, height, channels, slices, frames);

time = getTime();

// init GPU
run("CLIJ Macro Extensions", "cl_device=");
Ext.CLIJ_clear();

// send input image to the GPU
input = "input";
rename(input);
Ext.CLIJ_push(input);



// denoising
denoised = "denoised";
Ext.CLIJ_blur2D(input, denoised, 1, 1);




// pull the resulting image from the GPU and show it
Ext.CLIJ_pull(denoised);

1 Like

Hi Debora,

Robert will have a more accurate answer but here’s a few hints. I don’t think that the Clij functions are designed to handle multi-dimensional stacks. My impression is that they can operate on 2D images or 3D stacks. At best there are functions to selectively push parts from hyperstacks e.g. CLIJ_pushCurrentZStack. I think one workaround for you is to simply turn your hyperstack into a large z-stack (mixed channels), use the 3D blurring with z-blurring set to 0, and re-transform your stack to its original shape. Here’s an example using the mitosis.tiff sample:

//Grab a multiD image and get its dimensions
run("Mitosis (26MB, 5D stack)");
getDimensions(width, height, channels, slices, frames);
totslices = channels*slices*frames

//transform the hyperstack into one large z.stack
run("Hyperstack to Stack");
run("Properties...", "channels=1 slices=" +totslices+ " frames=1")


// init GPU
run("CLIJ Macro Extensions", "cl_device=");
Ext.CLIJ_clear();

// send input image to the GPU
input = "input";
rename(input);
Ext.CLIJ_push(input);

// blur using the 3D function AND using sigmaz = 0
denoised = "denoised";
Ext.CLIJ_blur3D(input, denoised, 5, 5,0);

// pull the resulting image from the GPU and turn it back into a hyperstack
Ext.CLIJ_pull(denoised);
run("Stack to Hyperstack...", "order=xyczt(default) channels="+channels+" slices="+slices+" frames="+frames+" display=Color");
Ext.CLIJ_pushCurrentZStack(String image);

I hope it helps.
Cheers,
Guillaume

2 Likes

Hi @Debora_KellerOlivier,

as @guiwitz introduced absolutely correctly (thanks btw!), CLIJ does not support multi-channel image data as such. There are two major reasons:

  • Many operations such as blurring, thresholding, connected components analysis don’t make much sense over channels. E.g. with blurring over channels you introduce cross-talk :ghost: Furthermore, when applying thresholding and connected components analysis over time you can get horrible false-segmentations. We discussed that earlier here.
  • Secondly, some GPUs are limited regarding memory. Thus, you may want to process images frame by frame and/or stack by stack in a loop. I actually suspect you want that, too :wink:

Let me point you to some examples which might be of your interest:

Batch processing

In the CLIJ preprint we discuss a batch-processing macro. You find it here. It’s a quite complex workflow processing stacks and counting spots.

I just wrote a simple batch-processing macro and put it here. You will see that batch-processing in CLIJ is basically the same as in ImageJ:

// go through the folder
for (i = 0; i < lengthOf(files); i++) {
	open(path_to_images + files[i]);
	rename(input);

	// push images to GPU
	Ext.CLIJ_push(input);
	
	// ...
	
	// Get results back from GPU
	Ext.CLIJ_pull(result);

	// save result
	saveAs("tif", path_to_results + files[i]);
	close();
}

Processing slices of stacks individually

For your workflow it may make sense that you push the whole stack (as @guiwitz showed) using the Hyperstack to Stack method and CLIJ_push. Then, you can copy individual slices using CLIJ_copySlice, process them as 2D images and afterwards copy them back into the stack. After you processed all images, you can pull the whole stack back and save it to disc. You could even run Stack to Hyperstack before saving to get it back in the right dimensionality. I recently programmed an example macro doing something similar for a 3-channel 2D image of my mentor.

// iterate over channels
for (c = 0; c < 3; c++) {
	Ext.CLIJ_copySlice("catRGB", "cat", c);
	// ...
	
	// apply transform
	Ext.CLIJ_applyVectorField2D("cat", "rotatedShiftX", "rotatedShiftY", "transformed");

	// put resulting 2D image in the right plane
	Ext.CLIJ_copySlice("transformed", "resultStack", i * 3 + c);
}

Last but not least a kind reminder from our workshop in Porto: Running a single operation such as blur on the GPU may not be faster than on the CPU because of the time we spend for pushing and pulling image data.

May I ask what kind of workflow you are planning to apply to your images?

Cheers,
Robert