Labelling not working

Hi,

I’m trying to write a Jython script where I use Clij for a standard filtering + labelling + regions stats pipeline. I started with “real” images and couldn’t get it to work so I made a minimal example using the blobs image which shows the same problem. As visible in the attached image, only some regions get labelled and the others not. Also, the results table is full of strange values.


I couldn’t find a description of labelling + regions stats in the Clij-Jython documentation and imported the functions that I believe should do the work, but it’s entirely possible I misused those functions. Here’s the script:

from ij import IJ, ImagePlus, WindowManager
from net.haesleinhuepf.clij import CLIJ;
from net.haesleinhuepf.clij.advancedfilters.StatisticsOfLabelledPixels import statisticsOfLabelledPixels;
from net.haesleinhuepf.clij.advancedfilters.ConnectedComponentsLabeling import connectedComponentsLabeling;
from net.haesleinhuepf.clij.coremem.enums import NativeTypeEnum;
from ij.measure import ResultsTable

#load and binarize blobs
IJ.run("Blobs (25K)");
imp = IJ.getImage()
imp.setTitle("blobs_gray");

#create results table
my_results = ResultsTable()

#get clij instance and push to GPU
clij = CLIJ.getInstance();
raw = clij.push(imp);
src = clij.create(raw);
dst = clij.create(raw);

#thresholding
clij.op().automaticThreshold(raw, src, 'Otsu');

#run labelling + stats
connectedComponentsLabeling(clij, src, dst)
statisticsOfLabelledPixels(clij, raw, dst, my_results)

#show output
my_results.show('cell_measures')

binary = clij.pull(src);
binary.show();
binary.setTitle("binary");

connect_comp = clij.pull(dst);
connect_comp.show();
connect_comp.setTitle("connect_comp");

Maybe @haesleinhuepf can help ?

Cheers,
Guillaume

2 Likes

Hi @guiwitz,

thanks for testing CLIJx! Sorry for the inconvenience: I was working recently on the connected components analysis (CCA) implementation and obviously screwed it up. Please update your Fiji to get the bug-fixed version.
Just mentioning: CCA is part of the experimental arm of CLIJ. That’s why it doesn’t show up in official the API reference yet. Anyway, I’m happy if people try experimental stuff. You find jython example code for CCA here and its yet uncomplete API reference here.

Furthermore, it is not recommended to import individual CLIJx classes and methods. Instead, it’s recommended to use the CLIJx gateway:

from net.haesleinhuepf.clijx import CLIJx;

#get clijx instance
clijx = CLIJx.getInstance();

# ...
clijx.connectedComponentsLabeling(src, dst)

Thus, I would recommend using the API for your example like this:

from ij import IJ, ImagePlus, WindowManager
from net.haesleinhuepf.clijx import CLIJx;
from ij.measure import ResultsTable

#load and binarize blobs
IJ.run("Blobs (25K)");
imp = IJ.getImage()
imp.setTitle("blobs_gray");

#create results table
my_results = ResultsTable()

#get clij instance and push to GPU
clijx = CLIJx.getInstance();
raw = clijx.push(imp);
src = clijx.create(raw);
dst = clijx.create(raw);

#thresholding
clijx.automaticThreshold(raw, src, 'Otsu');

#run labelling + stats
clijx.connectedComponentsLabeling(src, dst)
clijx.statisticsOfLabelledPixels(raw, dst, my_results)

#show output
my_results.show('cell_measures')

binary = clijx.pull(src);
binary.show();
binary.setTitle("binary");

connect_comp = clijx.pull(dst);
connect_comp.show();
connect_comp.setTitle("connect_comp");

# clean up GPU memory
raw.close();
src.close();
dst.close();

By doing so, you gain benefits of auto-completion in Fijis script editor:

Furthermore, accessing functions via clijx enables you copy pasting code between clijx, clatlab and clijpy as shown on twitter.

Again: Everything behind CLIJx is experimental. But your feedback is really appreciated. Just saying: Be a bit careful with functionality in there. It’s a construction site :wink:

Let me know how it goes!

Cheers,
Robert

2 Likes

Oh and one more thing: Instead of

binary = clijx.pull(src);
binary.show();
binary.setTitle("binary");

You can use the convenience method show():

clijx.show(src, "binary");

Cheers,
Robert

2 Likes

Hi @haesleinhuepf ,

great, this fixed the problem! Thanks for the explanation about how to properly use CLIJx, I kind of new I was doing something a bit edgy.

Now that it works, I have however an additional question :slight_smile:. What should one do with images that contains more than 255 objects ? When running the script e.g. on particles.gif, it labels all regions but when reaching 255, labels start over at 0, which then disrupts the measurements which are spanning the whole image. I tried to create the image receiving the labels as:

dst = clij.create(src.getDimensions(),NativeTypeEnum.Short)

This indeed creates a 16bit image with labels with values above 255 but now the image is all garbled up with stripes indicating I think an 8bit-16bit conversion problem as you can see below.

I completely understand that this is not part of the official Clij, so no problem if you don’t have time to fix this immediately. I’m just testing Clij on a project but can live with other plugins in the meantime.

Cheers,
Guillaume

1 Like

Hey @guiwitz,

would you mind trying

 dst = clij.create(src.getDimensions(),NativeTypeEnum.UnsignedShort)

Or Float?

Thanks!

Cheers,
Robert

1 Like

Fixed! Sorry, I could have figured that myself. Being more of a Python person I’m not used to these type names.

Anyway thanks for your great work! I like a lot the documentation with all the nice examples to just copy paste…

Cheers,
Guillaume

1 Like

Hi @haesleinhuepf

How can I work with clijx label functions with more than 255 objects using ImageJ macro language ?

I’m using:
CLIJx_morphoLibJFloodFillComponentsLabeling
CLIJx_excludeLabelsOutsideSizeRange
CLIJx_reduceLabelsToLabelledSpots
CLIJx_extendLabelsWithMaximumRadius

Thanks
Ofra

1 Like

Hi Ofra,

if you use CLIJ2_connectedComponentsLabeling instead of CLIJx_morphoLibJFloodFillComponentsLabeling it should just work. Apparently, there is a bug in my MorpholibJ-Wrapper, it generates images with 8-bit output when 8-bit input images are given. Thus, in order to make the CLIJx_morphoLibJFloodFillComponentsLabeling work, you need to call CLIJ2_convertFloat in advance. Is there a particular reason why you use the CLIJx-morpholibj extension here? I’m curious!

Here comes an example demonstrating the convertFloat:

run("CLIJ2 Macro Extensions", "cl_device=");

// make a test image
newImage("test", "8-bit noise", 1024, 1024, 1);
input = getTitle();
Ext.CLIJ2_push(input);
Ext.CLIJ2_gaussianBlur2D(input, blurred, 2, 2);
Ext.CLIJ2_detectMaxima2DBox(blurred, binary, 2, 2);

Ext.CLIJ2_convertFloat(binary, binary_float); // without that line, number of labels would be limited to 255

// Connected Components Labeling
Ext.CLIJx_morphoLibJFloodFillComponentsLabeling(binary_float, labels);

Ext.CLIJ2_getMaximumOfAllPixels(labels, maximum_of_all_pixels);
print("Num labels: " + maximum_of_all_pixels);

Thanks for reporting this issue! I will fix the extenions asap.

Let me know if this helps!

Cheers,
Robert

2 Likes

Hi Robert,

CLIJ2_convertFloat solved the problem when using CLIJx_morphoLibJFloodFillComponentsLabeling.

I also tried CLIJ2_connectedComponentsLabeling (without convertFloat) and it also works perfectly.

to answer your question: I used the CLIJx_morphoLibJFloodFillComponentsLabeling version because I converted code that used MorphoLibJ. So far I don’t see any preference for using it.

Thanks
Ofra

2 Likes

Hey @Ofra_Golani ,

I just uploaded the new clijx and assistant releases which contain the bug-fixes of the Connected Components Labeling extensions from MorphoLibJ, Imglib2, ImageJ3DSuite and BoneJ. Futhermore, the other bug of CLIJx_reduceLabelsToLabelledSpots you reported is also fixed.

Let me know if you experience any further issues!

Thanks again for reporting these. You made clij better this week :slight_smile:

Cheers,
Robert