Yes. I’m on it
Thanks for your patience
Yes. I’m on it
Thanks for your patience
I spent some time yesterday testing the CLIJ2 plugins via the GUI in ImageJ 1.53 and am impressed with its speed and ease of use. Most functions will work as drop-in replacements of existing ImageJ functions.
Is this there any forum dedicated to the development and use of CLIJ; or is this the place, using clij as a tag on the posts?
glad to hear you like clij!
They are intended to be. However, there are sometimes tiny differences as reported in the paper and in the FAQ. Furthermore, we recently wrote this chapter which explains how to do the macro -> clij-macro switch.
I’m currently fixing the image1-compatibilty. Feel free to play a bit with clij in Fiji in the meantime. I keep you posted.
Hey Stein @steinr ,
I just updated clij2-imagej. Would you mind testing version 18.104.22.168 ? In order to make your macros run, you also need to change “CLIJ2 Macro Extensions” to “CLIJ2 Legacy Macro Extensions”. I also added a comment to the website. It’s possible that this change is no longer necessary in a future release, but for now this workaround is necessary.
Thanks for reporting this bug!
Thank you for the quick fix,
yes now it works!
This is my test macro, as adapted from the macro recorder:
run("CLIJ2 Legacy Macro Extensions", "cl_device=[Quadro M5000M]"); run("Close All"); run("T1 Head (16-bits)"); // reslice left image1 = "t1-head.tif"; image2 = "t1-resliced"; Ext.CLIJ2_push(image1); Ext.CLIJ2_resliceLeft(image1, image2); Ext.CLIJ2_pull(image2);
I am using the daily build of ImageJ 1.53e in Windows 10/64.
The recorder records the loading of the plugin as
run("CLIJ2 Macro Extensions"... so the
Legacy word should eventually be removed to avoid confused users. Or the plugin could record it as
"CLIJ2 Legacy Macro Extensions" when it is running in ImageJ 1.x.
Yes, that’s the goal. This would also allow to run macros recorded in Fiji… Pretty sure this will come at some point. I hope it’s ok in the meantime and I also promise to keep the legacy extensions to not break your workflows later
Thanks again for testing and reporting. You made clij better today!
The bottleneck in my workflow is a task where I scale down (by a factor 2) 16-bit stacks of size 2000x2000x2000 voxels, then reslice and project them in all three directions. I think the reslicing is what consumes the most time here. I have not done any serious benchmarking but just accepted that this can take some time. I do typically 8 of these every day I have a booking at our µCT lab. The processing can take up to 15 minutes per stack so this translates to two hours waiting time until I can move the results out of the lab (I have only a few hundred GB available for temporary storage). The GPU on the computers I use can only take < 2GB stacks, but I can scale to 8-bit without losing any visual information, so that should be doable in the GPU as 1000x1000x1000 voxels stacks at 1GB each. I will let you know how this goes when I get around to implement this in CLIJ. I now see that this is a feasible way to go, as CLIJ can do the reslicing very fast.
I have been playing around some time with CLIJ2 in ImageJ 1 the last couple of days, and I think that the most obvious limitation is that out of the box, the error messages are not shown anywhere in ImageJ 1 as there is no console window visible there by default. If I launch ImageJ from the command line using the --console option, the messages are shown as expected on the command line. But the Windows command line window is clumsy to use, as one must change the command text buffer size in Windows settings to make it scrollable. I suppose this is an option known only to advanced users. Anyway, I found it very convenient to use an external programmers’ editor (I use EditPlus) for the macro development, because it grabs the output from stdout and shows it in a docked window. Then I can easily scroll there to see the CLIJ error messages.
My point is that CLIJ2 would be even more user-friendly if there was an option somewhere to specify where the CLIJ error messages should be written. Then one could choose between stdout/console, the ImageJ “Log” window, or perhaps even better would be to have a dedicated text window that showed the CLIJ error messages separately. The advantage of this (also applicable to Fiji users) is that one would then not have to scroll past all the java error lines to locate the CLIJ error messages. The CLIJ messages are very informative and essential when developing a workflow, as one can then determine what went wrong (usually a too-little-memory-available issue).
I’m happy to hear that it works and glad that you like it.
I’m not sure if this is a limitation of CLIJ or a limitation of ImageJ.
Wow, that’s a cool solution! I didn’t know this tool. A potential alternative is copying
ImageJ.exe and renaming it to
debug.exe. It would then automatically open a console in the background when you double click on it:
That is a great idea, but I’m not sure if this is easily achievable. CLIJ uses the Java standard way of showing error messages: Exceptions. If one wants to supress error messages or display it in any other place, one would have to do this one framework side. That’s why Fiji has the console window:
What I’m saying is: I’m not so much a fan of re-inventing the wheel.
Btw. did you try CLIJ from Fiji? I spent quite some time to make it as accessible as possible from the script editor. I could imagine that some errors wouldn’t even happen if the code was written using auto-completion:
Thanks for mentioning that I also spend quite some time on optimising this part.
Just out of curiousity: Can you share some details why you want to develop the workflow in plain ImageJ?
Thanks again for the feedback. It’s really appreciated!
Side note: Have you tried activating batch mode while reslicing using normal ImageJ methods? I think reslicing becomes significantly faster when batchmode is
I think it is an (intentional) limitation of ImageJ that the console window is not visible, as you rarely need it. I don’t know of any other way than activating it on the command line, perhaps someone else know this?
Thanks for the tip, I did not know this! I will try that.
Edit Plus is a great program! It is shareware at $35 but well worth the money, as it is easy to add syntax coloring and custom shortcuts for running your script in other applications. It is also easy to edit text as vertical selections, which is very useful when you have tables or repeating code lines. When working on computers that I do not own myself, I use Notepad++ as it is free. I have not checked out if that can also grab output as Edit Plus can, maybe it can as well.
Yes I tried it from Fiji first. Yes, the auto-completion feature works great!
A big problem is that my existing macros where I try to add CLIJ2 code get messed up if I try to edit them in the Fiji script editor. It is a line ending issue; whenever I add some text the line endings in that text is missing both in EditPlus and the ImageJ text editor. Perhaps this can be solved by setting the file format to Linux or Mac style from the start, I will check that out.
I like the simplicity and speed of ImageJ 1. I am a scientist and not a programmer, so cutting and pasting code found somewhere and just doing a “Compile and Run” makes it easy to write new or modify existing plugins. Since my work is purely project-based, I do not have the resources nor time to learn tools such as Maven or Eclipse.
Another and more important reason for me not using Fiji as my primary tool is that a majority of my workflow is based on launching code from somewhere else (command line on Windows, right-clicks in Explorer) and the very long launch time of Fiji (tens of seconds, often several minutes) slows my workflow a lot compared to ImageJ 1.x which launches in just a tiny fraction of a second. I usually launch ImageJ and close it for every single desired task (probably hundreds of times per day), which is started by right-clicking the data file or folder of interest in Windows and selecting what to do from a menu I have created there. This makes multi-tasking easy as I can have as many instances I want running parallel threads of batch macros without any cross-interference. I control what goes where using the -port option from my Windows scripts. Yes I know that much of this could be fixed by running everything in headless mode, but I like to see on screen how the macros proceed, so that I can take action if if something is wrong or will take too long time to execute.
Also, there are few of the bundled plugins in Fiji that are useful for me since I am a materials scientist and do not work with biology. I prefer to install single plugins that are useful to me (such as the 3D tools and CLIJ2) in ImageJ 1. This nearly always works fine; whenever there are dependencies I just copy the dependency jars as well over to ImageJ 1 and put them in the same subfolder. CLIJ1 worked fine this way when I tested it.
I still use Fiji as my first stop when testing stuff described or linked to from imagej.net. The Fiji update sites makes it very easy to install plugins with complex dependencies. Then I can test the plugins first to see if it is worth including in my workflow, as I did with CLIJ2.
Yes I have tried that. Reslicing is still slow under batch mode. I think the performance difference is only a few percent better. I also see that reslicing from left-right is much slower than top-down with the normal ImageJ methods. Perhaps the memory handling is done inefficiently?
Sure! That makes so much sense!
That’s also an amazing trick!
If you work with a dedicated graphics card, GDDR RAM is just faster than DDR RAM. Furthermore, GPUs are massively parallel. Maybe that’s it.
Thanks for the feedback! I learned a lot. Great discussion
I did not mean when comparing normal methods to CLIJ, but when comparing normal reslice top-down to normal reslice left-right. I haven’t benchmarked this but I think the latter is something like 5 times slower.
I checked now, normal reslice left-right is 15 times slower than top-down!
And CLIJ2 reslice left-right is 350 times faster than normal left-right!!
Stack size: 2000x2000x1000 Time for ImageJ to Open File: 2.331 Time for ImageJ Downsample Nearest: 11.426 Time for ImageJ Downsample Interpolated: 62.67 Stack size: 1000x1000x500 Time for ImageJ Reslice Left-Right: 242.763 Time for ImageJ Reslice Top-Bottom: 16.165 Stack size: 2000x2000x1000 Time for ImageJ to Open File: 2.122 Time for CLIJ2 (Quadro M5000M) Push: 1.826 Time for CLIJ2 (Quadro M5000M) Downsample (Nearest): 0.073 Stack size: 1000x1000x500 Time for CLIJ2 (Quadro M5000M) Reslice Left-Right: 0.694 Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom: 0.08
OMG. You’re doing a year of work on a single day
I did not realize before I did these benchmarks that I can rotate the dataset 90 degrees clockwise (that is pretty quick) and then do the quicker reslice top-down to get identical results as reslice left-right, more than 10 times faster. Here are the benchmarks for that:
Stack size: 1000x1000x500 Time for ImageJ Rotate Right: 0.939 Time for ImageJ Reslice Top-Bottom: 15.343
Obviously the ImageJ reslice left-right code is written inefficiently for this orthogonal case. Perhaps because it includes the possibility for interpolated and inclined selections?
I tried to see if there is a speed difference in reslice left-right vs rotate+reslice top-bottom in CLIJ2 too, and yes there is, but it is much smaller than in regular code. Rotate CW + Reslice TB is 3 times faster than Reslice LR. Times are in seconds.
Stack size: 1000x1000x500 Time for CLIJ2 (Quadro M5000M) Reslice Left-Right: 0.538 Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom: 0.069 Stack size: 1000x1000x500 Time for CLIJ2 (Quadro M5000M) Rotate CW: 0.085 Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom: 0.086
That’s indeed very interesting! Can you share the code for reproducing this?
// init GPU device = "HD Graphics 530 "; device = "Quadro M5000M"; ImageJversion = getVersion(); print("ImageJ Version: " + ImageJversion); if (ImageJversion >= "2.1.0") run("CLIJ2 Macro Extensions", "cl_device=[&device]"); else run("CLIJ2 Legacy Macro Extensions", "cl_device=[&device]"); Ext.CLIJ2_getGPUProperties(GPU_name, global_memory_in_bytes, OpenCL_version); Ext.CLIJ2_clear(); //prepare demo data run("T1 Head (16-bits)"); //run("Scale...", "x=4 y=4 z=4 width=1024 height=1024 depth=516 interpolation=Bicubic average process create"); image1 = getTitle; selectImage(image1); getDimensions(width, height, channels, slices, frames); print("Stack size: "+width+"x"+height+"x"+slices+""); time = getTime; Ext.CLIJ2_push(image1); //Ext.CLIJ2_reportMemory(); print("Time for CLIJ2 ("+GPU_name+") Push: ", (getTime-time)/1000); //resample stack to a bigger image size image2 = "resampled"; factor_x = 4.0; factor_y = 4.0; factor_z = 4.0; time = getTime; //the following is confusing: //we need to use CLIJ2_downsample3D to resample up/bigger, //and CLIJ2_resample to downsample/smaller by the given factors. Ext.CLIJ2_downsample3D(image1, image2, factor_x, factor_y, factor_z); //Ext.CLIJ2_resample(image1, image2, factor_x, factor_y, factor_z, true); print("Time for CLIJ2 ("+GPU_name+") Resample Nearest: ", (getTime-time)/1000); Ext.CLIJ2_release(image1); Ext.CLIJ2_pull(image2); //Ext.CLIJ2_reportMemory(); // reslice right selectImage(image2); getDimensions(width, height, channels, slices, frames); print("Stack size: "+width+"x"+height+"x"+slices+""); image3 = "resliced_right"; time = getTime; Ext.CLIJ2_resliceLeft(image2, image3); print("Time for CLIJ2 ("+GPU_name+") Reslice Left-Right: ", (getTime-time)/1000); Ext.CLIJ2_pull(image3); // rotate selectImage(image2); getDimensions(width, height, channels, slices, frames); print("Stack size: "+width+"x"+height+"x"+slices+""); image3 = "rotated"; time = getTime; Ext.CLIJ2_rotateClockwise(image2, image3); print("Time for CLIJ2 ("+GPU_name+") Rotate CW: ", (getTime-time)/1000); Ext.CLIJ2_pull(image3); // reslice top selectImage(image3); getDimensions(width, height, channels, slices, frames); print("Stack size: "+width+"x"+height+"x"+slices+""); image4 = "resliced"; time = getTime; Ext.CLIJ2_resliceTop(image3, image4); print("Time for CLIJ2 ("+GPU_name+") Reslice Top-Bottom: ", (getTime-time)/1000); Ext.CLIJ2_pull(image4); Ext.CLIJ_clear();
I wrote this macro for ImageJ 1, but the timing results are only marginally slower when run in ImageJ 2 (Fiji). The use of getVersion will enable this macro to work unchanged in both versions of ImageJ.
Here are the timings from the daily build of ImageJ 1.53x:
ImageJ Version: 1.53f Stack size: 256x256x129 Time for CLIJ2 (Quadro M5000M) Push: 0.018 Time for CLIJ2 (Quadro M5000M) Resample Nearest: 0.124 Stack size: 1024x1024x516 Time for CLIJ2 (Quadro M5000M) Reslice Left-Right: 0.726 Stack size: 1024x1024x516 Time for CLIJ2 (Quadro M5000M) Rotate CW: 0.137 Stack size: 1024x1024x516 Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom: 0.127
And the same from newly updated Fiji:
ImageJ Version: 2.1.0/1.53c Stack size: 256x256x129 Time for CLIJ2 (Quadro M5000M) Push: 0.019 Time for CLIJ2 (Quadro M5000M) Resample Nearest: 0.151 Stack size: 1024x1024x516 Time for CLIJ2 (Quadro M5000M) Reslice Left-Right: 0.742 Stack size: 1024x1024x516 Time for CLIJ2 (Quadro M5000M) Rotate CW: 0.151 Stack size: 1024x1024x516 Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom: 0.129
I ran the macro on a Dell 7710 (2015 model) laptop with 64GB RAM and 8GB Nvidia graphics card. A newer PC will probably be much faster.
I found a solution to the above in this post:
IJ.log("Test1"); LogStream.redirectSystem(); System.err.println("Hello World!"); IJ.log("Test2");
After running this, the CLIJ2 error messages are written to the Log window instead of the Console. This allows us to capture the error messages and do actions in a macro based on them, if desired.