Volumetric segmentation and labeling of tiny droplets on a noisy background

Greetings good people,

I have many z-stacks of images, and I need count the number of droplets and to measure their volume (or surface, they can be safely assumed to be spherical). I also need to automatize the process, as I have many stacks.

Despite the large amount of plugins available on Imagej to segment and label 3D images, I never managed to get good results due to two reasons: my pictures are very noisy and the droplets are tiny, with some being just a few pixels wide.

Here is an example of the raw data:

Luckly, I managed to improve the noise on my data thanks to the excellent noise2void plugin, but the problem of very small droplets remains. Here is an example:

As I said above, I tried several plugins but with little success:

  • Droplet Counter is really messy, and gives me really inconsistent results everytime.

  • Trackmate is very good, but not in this situation. It indiscriminately fits the estimated diameter on every blob, and therefore it doesn’t give a reasonable estimate of the droplet size. Also, it can’t be used in scripts, as it wants to run on its GUI at every cost.

  • 3D Iterative Thresholding from the 3D ImageJ Suite seemed to be tailor made for this problem, but it gives wildly inconsistent results on my data despite having done a good amount of work to fine-tune its parameters. Sometimes it refuses to recognize some droplets, especially the most clustered ones. The other plugins from the same packaged worked somehow worse on my data

  • Classic Watershed from the MorphoLibJ seemed also to work, but understimates the number of droplets consistently. Note that I used the Subtract Background function from imagej and then used a very mild gaussian filter on the data beforehand, as it had the tendency to “split” in two parts some droplets.

  • Trainable Weka Segmentation seems pretty promising, but the built-in tools for training the images are pretty rough, and very often the plugin “melts” together two droplets. I think that this problem can be mitigated through extra training, but I haven’t been having much luck.

And on top of that, even when I somehow manage to get a passable segmentation, I stumble on another problem when trying to collect the statistics when using 3D Objects Counter.
Sometimes it “connects” droplets that seemingly don’t have any pixels in common, just like in this case:


Look at “droplet” number 77.

I believe that the problem lies in it not taking into account that the droplets are spheres, and therefore it “forcefully” connects everything above and below. This obviously messes up any estimation of the size of the droplets.

Has anyone ever faced the same problem when segmenting?
Is there any way to label and get the statistics of my segmented data that takes into account the (almost) sphericity of my droplets?

Thank you in advance!

Hi,

if Trackmate does in principle a good job at detecting the objects, why not use it as a start to find the droplet centers and then use this as seeds for segmentation in a next step?

Nope, Trackmate can be scripted quite nicely: Scripting TrackMate - ImageJ

A bit of self-advertisement: I once wrote a plugin using the Trackmate detector at its core to compute Colocalization of Spots. But it turned out to be also very convenient for just getting all detected spot positions quickly filled automatically into a results table + macro recorded (link here)

Next step for you would then be to use the spot positions as seeds (=create a label image with individual pixels labelled), threshold your original image, and do watershedding from seed points (e.g. from Morpholibj).

1 Like

First off, thank you a lot for your brilliant idea and your plugin (which runs faster than “stock” Trackmate, but I guess it is to be expected, as it doesn’t have the whole “track” part :wink: )

However, I have a question about this:

Is there any way to do this in imageJ? That would make the whole process much easier to automatize.

Also, even if I watershed the result, how do I get the object finder to properly recognize a droplet, meaning that it won’t connect regions that actually aren’t connected? (see the last example in the first post)

Thank you!

Hi,

ok it turned out to be a significantly more complex than I thought to automatize this but here is something for you to start. I’m adding some snippets in IJ macro but if you explain more what your exact output currently looks like and what your scripting knowledge (jython? ) is one can go into more details.

Anyway, here is a snippet to create a test image for anyone who wants to reproduce this:

// creates artifical test image with some spots
newImage("testimage", "8-bit noise", 200, 200, 100);
run("32-bit");
run("Gaussian Blur...", "sigma=2 stack");
setOption("BlackBackground", true);
setAutoThreshold("Triangle dark stack");
run("Convert to Mask", "method=Triangle background=Dark black");
run("Gaussian Blur...", "sigma=2 stack");

// and threshold it for the mask
run("Duplicate...", "duplicate");
setAutoThreshold("Huang dark stack");
run("Convert to Mask", "method=Default background=Dark black");
rename("mask");

testinput

Then you need to detect the spots, and I now used the option to add them to the roimanager als multipoint-roi. Select the testimage and run this macro.

// detect spots in active image
run("SpotDetector", "channel=1 radius_um=5.0 threshold=2000.0 domedian=false cleartable=true addtoroimanager=true");

And now to your question: every spot center should be the “seed” (=start) of a labelled region (=one individual spot). For this we need to create a seed image:

// start with a black image for the seed points, of same image dimensions
getDimensions(width, height, channels, slices, frames);
newImage("seeds", "16-bit black", width, height, slices);

// select the spots multipoint roi
roiManager("select", 0);

// loop over all points in it and set the pixel value to the labelID
Roi.getContainedPoints(xpoints, ypoints);
count=lengthOf(xpoints);

for (i = 0; i < count; i++) {
	slice=Roi.getPointPosition(i);
	// draw the seed point, every point with a different labelID
	Stack.setSlice(slice);
	setPixel(xpoints[i], ypoints[i], i);
}

run("Select None");

The ’ seeds’ image looks a bit boring but its exactly what we need. You see on the histogram that it has 951 values.

And now finally, Marker-controlled Watershed from MorpholibJ library yields ( glasbey LUT):
labelimage

You see that touching spots are split. Getting the volume measures now is easy: MorpholibJ > Analyze Regions 3D.


Another thought: have you tried Interactive H Watershed as alternative? It’s a super convenient tool also.

First off, I apologize for the long time between answers. I wanted to thank you deeply for your great work, but sadly it doesn’t work for my problem, as the result I get is this

even though spot detector works great, and gives this result

Interactive H watershed seems to give decent results, but sadly it still looks like it is not quite enough accurate for what I need. The problem is that (as you may see) the background noise is very “grainy” despite me denoising with the excellent n2v, and I can’t afford to use any kind of median or gaussian filtering, as they would “melt” close droplets together

Anyways, thank you deeply for your time