|
| 1 | + |
| 2 | + |
| 3 | +# Comparing Workflows: ImageJ versus CLIJ |
| 4 | +Robert Haase, March 2020 |
| 5 | + |
| 6 | +This page shows how to compare ImageJ based workflow with their |
| 7 | +translations using CLIJ. |
| 8 | + |
| 9 | +Let's start with ImageJ. We have a workflow loading an image, |
| 10 | +processing with background subtracting and thresholding. Note |
| 11 | +the two lines using the `getTime()`. |
| 12 | + |
| 13 | +```java |
| 14 | + |
| 15 | +// Get test data |
| 16 | +open("https://github.com/clij/clij2-docs/raw/master/src/main/resources/Lund_MAX_001300.tif"); |
| 17 | +rename("input_imagej"); |
| 18 | + |
| 19 | +start_time_imagej = getTime(); |
| 20 | + |
| 21 | +// subtract background in the image |
| 22 | +run("Duplicate...", "title=background_subtracted_imagej"); |
| 23 | +run("Subtract Background...", "rolling=25"); |
| 24 | + |
| 25 | +// theshold the image |
| 26 | +run("Duplicate...", "title=thresholded_imagej"); |
| 27 | +setAutoThreshold("Default dark"); |
| 28 | +setOption("BlackBackground", true); |
| 29 | +run("Convert to Mask"); |
| 30 | + |
| 31 | +end_time_imagej = getTime(); |
| 32 | +``` |
| 33 | +<a href="images/compare_workflows/image_1585300495290.png"><img src="images/compare_workflows/image_1585300495290.png" width="250" alt="input_imagej"/></a> |
| 34 | +<a href="images/compare_workflows/image_1585300495701.png"><img src="images/compare_workflows/image_1585300495701.png" width="250" alt="background_subtracted_imagej"/></a> |
| 35 | +<a href="images/compare_workflows/image_1585300496684.png"><img src="images/compare_workflows/image_1585300496684.png" width="250" alt="thresholded_imagej"/></a> |
| 36 | + |
| 37 | + |
| 38 | +Now we run the same workflow with CLIJ |
| 39 | + |
| 40 | +```java |
| 41 | + |
| 42 | +// Get test data |
| 43 | +open("https://github.com/clij/clij2-docs/raw/master/src/main/resources/Lund_MAX_001300.tif"); |
| 44 | +rename("input_clij"); |
| 45 | + |
| 46 | +start_time_clij = getTime(); |
| 47 | + |
| 48 | +// Init GPU |
| 49 | +run("CLIJ Macro Extensions", "cl_device="); |
| 50 | +Ext.CLIJ2_clear(); |
| 51 | + |
| 52 | +// push data to GPU |
| 53 | +Ext.CLIJ2_push("input_clij"); |
| 54 | + |
| 55 | +// subtract background in the image |
| 56 | +radius = 25; |
| 57 | +Ext.CLIJ2_topHatBox("input_clij", "background_subtracted_clij", 25, 25, 0); |
| 58 | +Ext.CLIJ2_pull("background_subtracted_clij"); |
| 59 | + |
| 60 | +// threshold the image |
| 61 | +Ext.CLIJ2_automaticThreshold("background_subtracted_clij", "thresholded_clij", "Default"); |
| 62 | +Ext.CLIJ2_pullBinary("thresholded_clij"); |
| 63 | + |
| 64 | +end_time_clij = getTime(); |
| 65 | + |
| 66 | +``` |
| 67 | +<a href="images/compare_workflows/image_1585300498007.png"><img src="images/compare_workflows/image_1585300498007.png" width="250" alt="input_clij"/></a> |
| 68 | +<a href="images/compare_workflows/image_1585300498425.png"><img src="images/compare_workflows/image_1585300498425.png" width="250" alt="background_subtracted_clij"/></a> |
| 69 | +<a href="images/compare_workflows/image_1585300499005.png"><img src="images/compare_workflows/image_1585300499005.png" width="250" alt="thresholded_clij"/></a> |
| 70 | + |
| 71 | +The results look similar. There are difference because the |
| 72 | +implementation of ImageJ background subtraction is close to but |
| 73 | +not identical to CLIJs topHatBox filter. Furthermore, CPU and GPUs |
| 74 | +do computation a bit differently. |
| 75 | + |
| 76 | +## Quantitative image comparison |
| 77 | + |
| 78 | +You may have noticed already, all intermediate images got new names. |
| 79 | +This allows us now to compare them. |
| 80 | + |
| 81 | +Let's start with quantitative measurements on the images and |
| 82 | +processing durations. |
| 83 | + |
| 84 | +```java |
| 85 | +// configure measurents, clean up before |
| 86 | +run("Set Measurements...", "area mean standard min redirect=None decimal=3"); |
| 87 | +run("Clear Results"); |
| 88 | + |
| 89 | +// measure in the image from the imagej workflow |
| 90 | +selectWindow("background_subtracted_imagej"); |
| 91 | +run("Measure"); |
| 92 | +selectWindow("thresholded_imagej"); |
| 93 | +run("Measure"); |
| 94 | + |
| 95 | +// measure in the image from the imagej workflow |
| 96 | +selectWindow("background_subtracted_clij"); |
| 97 | +run("Measure"); |
| 98 | +selectWindow("thresholded_clij"); |
| 99 | +run("Measure"); |
| 100 | + |
| 101 | +//Table.rename("Results", "Quantitative measurements"); |
| 102 | + |
| 103 | +``` |
| 104 | +<table> |
| 105 | +<tr><th>Area</th><th>Mean</th><th>StdDev</th><th>Min</th><th>Max</th></tr> |
| 106 | +<tr><td>524288</td><td>43.772</td><td>89.125</td><td>0</td><td>888</td></tr> |
| 107 | +<tr><td>524288</td><td>25.184</td><td>76.077</td><td>0</td><td>255</td></tr> |
| 108 | +<tr><td>524288</td><td>53.027</td><td>93.718</td><td>0</td><td>904</td></tr> |
| 109 | +<tr><td>524288</td><td>28.614</td><td>80.485</td><td>0</td><td>255</td></tr> |
| 110 | +</table> |
| 111 | + |
| 112 | + |
| 113 | +From these measurements we can conclude that there are small differences |
| 114 | +between the background subtracted images, but apparently smaller differences |
| 115 | +between the binary result images. |
| 116 | + |
| 117 | +We can verify that by visualising |
| 118 | +differences visually. Note that we choose to save the subtraction images |
| 119 | +in 32-bit because 8-bit images don't support negative values. |
| 120 | + |
| 121 | +## Visual differences between background_subtracted images |
| 122 | + |
| 123 | +```java |
| 124 | +imageCalculator("Subtract create 32-bit", "background_subtracted_imagej","background_subtracted_clij"); |
| 125 | + |
| 126 | +``` |
| 127 | +<a href="images/compare_workflows/image_1585300499308.png"><img src="images/compare_workflows/image_1585300499308.png" width="250" alt="Result of background_subtracted_imagej"/></a> |
| 128 | + |
| 129 | +## Visual differences between thresholded images |
| 130 | + |
| 131 | +```java |
| 132 | +imageCalculator("Subtract create 32-bit", "thresholded_imagej","thresholded_clij"); |
| 133 | + |
| 134 | +``` |
| 135 | +<a href="images/compare_workflows/image_1585300499934.png"><img src="images/compare_workflows/image_1585300499934.png" width="250" alt="Result of thresholded_imagej"/></a> |
| 136 | + |
| 137 | +This confirms visually our assumption: The background_subtracted images |
| 138 | +are a bit different while the binary result images are not. |
| 139 | + |
| 140 | +## Comparing processing time |
| 141 | + |
| 142 | +Let`s now also compare the different processing times: |
| 143 | + |
| 144 | +```java |
| 145 | + |
| 146 | +print("ImageJ took " + (end_time_imagej - start_time_imagej) + "ms."); |
| 147 | +print("CLIJ took " + (end_time_clij - start_time_clij) + "ms."); |
| 148 | + |
| 149 | +``` |
| 150 | +<pre> |
| 151 | +> ImageJ took 439ms. |
| 152 | +> CLIJ took 110ms. |
| 153 | +</pre> |
| 154 | + |
| 155 | +The numbers shown here depend on used GPU hardware. Let's therefore it's |
| 156 | +good practice to document which GPU was used: |
| 157 | + |
| 158 | +```java |
| 159 | + |
| 160 | +run("Clear Results"); |
| 161 | +Ext.CLIJ2_getGPUProperties(); |
| 162 | + |
| 163 | +``` |
| 164 | +<table> |
| 165 | +<tr><th>GPUName</th><th>Global_memory_in_bytes</th><th>OpenCL_version</th></tr> |
| 166 | +<tr><td>GeForce RTX 2060 SUPER</td><td>8589934592.000</td><td>1.200</td></tr> |
| 167 | +</table> |
| 168 | + |
| 169 | + |
| 170 | +Note: If you run this script a second time, numbers may be a bit different, |
| 171 | +especially CLIJ becomes faster because the so called warmup period is over. |
| 172 | +During this period, code is compiled. This compilation takes time and thus, |
| 173 | +when doing it a second time, processing can be significantly faster. |
| 174 | +Furthermore, there are always fluctations in time measurements. Thus, |
| 175 | +it is recommended to run such workflows many times in a loop and doing |
| 176 | +statistics on derived measurements. |
| 177 | + |
| 178 | +Last but not least, let's clean up by closing all windows and emptying |
| 179 | +GPU memory: |
| 180 | + |
| 181 | +```java |
| 182 | + |
| 183 | +run("Close All"); |
| 184 | +Ext.CLIJ2_clear(); |
| 185 | +``` |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | +``` |
| 190 | +``` |
0 commit comments