# Calculate bubble areas in a foam picture. How to fill all holes?

Tags: #<Tag:0x00007fb879465918> #<Tag:0x00007fb8794657b0>

#1

I am beginner of ImageJ. Currently I am calculating bubble areas in attachment. When I make image binary and fill holes, I get an Image which you can see in the second file attached. There are still a lot of bubbles(holes) needed to be filled in order to calculate their area, the reason is that some circles are disconnected. Does anyone know how to make these circles connected or other ways to calculate bubble area in the first file attached?

#2

You want something like this, no? Or more precise edge detection, maybe. I am new to measuring bubbles.

Itâ€™s missing the elongated bubble in the top right, and there are some artefact ROIs between bubbles (38, 101). But these are easily removed.

Total surface area is 166777.

#3

Yes, sure. Thatâ€™s exactly what I want. Of course, it would be better to be more precise. Could you please tell me how you manage to do it?

#4

I will get back to you once Iâ€™m on my computer, but the really quick work I did for this example pic:

Process >> Find edges

Process â€¦ fill holes.

Analyze particles, set size to smallest to largest bubbles. Set desired circularity of bubbles.

Then simply measure the area of this selection.

Maybe I applied some more preprocessing, I will get back to you with details.

HTH,
Sverre

#5

thanks, following your steps, I still canâ€™t get desired results and I donâ€™t know which step I miss.

#6

This is what i did from the macro recorder, play around with different filters and the analyze particles parameters to see if you can improve it. You can also try the trainable weka segmentation, it is well documented and you will find guides on youtube!

``````    run("Find Edges");
run("Make Binary");
run("Fill Holes");
selectWindow("bubbles.JPG");
run("Analyze Particles...", "size=200-16000 circularity=0.28-1.00 show=Outlines display summarize add");``````

#7

This is a result following your macros. Whatâ€™s wrong with it?

#8

Good day Hao Wang,

working with thresholds is difficult and most often they donâ€™t generalize wellâ€¦

For your example image you may try the following ImageJ-macro:

///////////////macro start///////////////
requires(â€ś1.51kâ€ť);
run(â€śSet Measurementsâ€¦â€ť, â€śarea_fraction redirect=None decimal=3â€ť);
run(â€ś32-bitâ€ť);
setAutoThreshold(â€śMean darkâ€ť);
run(â€śInvert LUTâ€ť);
setOption(â€śBlackBackgroundâ€ť, true);
run(â€śDilateâ€ť);
run(â€śMeasureâ€ť);
run(â€śShow Allâ€ť);
///////////////macro end///////////////

It gives you the following result image with a pore area fraction of 67.76%.

Evidently, there are two glitches at the bottom right and partial pores at the borders are missing.

You may adjust the Particle Size as well as the Particle Circularity.
Furthermore, you may repeat â€śDilateâ€ť and if bubbles fuse, you may separate them by introducing

run(â€śWatershedâ€ť);

Good luck and be successful

Herbie

#9

I have no idea how you ended up there, can you open your macro recorder, do this again and then copy/paste the record?

plugins >> macros >> recorder

#10

Good day Sverre GrĂ¸dem

the macro was created by using the macro recorder.

If the macro does what you want, why should I paste the result of the recorder again?

If you are unclear about the processing steps, then you should consult the ImageJ manual:
https://imagej.nih.gov/ij/docs/guide/index.html

Regards

Herbie

#11

I was replying to HW315, no?

You are both Hâ€¦

#12

Sorry Sverre GrĂ¸dem,

for my wrong interpretation. In any case it was my fault!

Best

Herbie

#13

Thanks Herbie. I got a similar result as you suggested. One quick question: when running Analyze particles, does ImageJ find the edges of grayscale 255 or grayscale 0?

#14

selectWindow(â€śrawimage.JPGâ€ť);
run(â€śFind Edgesâ€ť);
run(â€śMake Binaryâ€ť);
run(â€śFill Holesâ€ť);
run(â€śAnalyze Particlesâ€¦â€ť, â€śsize=200-16000 circularity=0.28-1.00 show=Outlines display summarize addâ€ť);

#15

Mmh,

â€śAnalyze Particlesâ€¦â€ť actually does no edge finding in the sense run(â€śFind Edgesâ€ť) does. It simply takes the binarized image produced by setAutoThreshold(â€śA Methodâ€ť).

However, â€śAnalyze Particlesâ€¦â€ť assumes bright (255) particles on dark (0) background.

HTH

Herbie

#16

Thanks you. In my case, gas in bubbles and liquid between bubbles are bright, bubble edges are dark. As you said, when I analysis particle size, if I donâ€™t restrict size range, does that mean liquid between bubbles is also count as particle?

In addition, I want to count bubble area, but threshold doesnâ€™t achieve a precise result. Do you have any suggestions? Like taking a clearer photo?

#17

Hao Wang,

the quality of your image isnâ€™t bad at all. I think it is taken quite carefully, but of course there is always â€śroomâ€ť for improvements â€¦

As Iâ€™ve written before, thresholding doesnâ€™t generalize well.

However, you should think about an objective measure of precision first. E.g. you could draw ROIs by hand and determine the percentage bubble area plus/minus an allowed tolerance. This would help with finding appropriate approaches.

My current estimate is that the bubble area fraction is 75%Â±5%.

Regards

Herbie

#18

Ok Hao, I had some more time and wrote a short ad hoc script for your analysis. This utilizes the trainable weka segmentation plugin. I trained a quick example classifier for you, but I encourage you to make your own, and train it on more than one image, see how robust you can make it! You can for sure improve on the one I made in 5 minutes. Once you have your classifier you can automate this whole procedure, you can run it on files in a directory or large stacks, whatever you prefer.

Regarding making a classifier for WEKA: Video, detailed wiki.

Code in python, copy paste from here to File >> new >> script in IJ. Select language python.

Download the classifier I trained. Remember to set the path to the classifier in the script.

``````from ij import IJ, WindowManager
from trainableSegmentation import WekaSegmentation
import Watershed_Irregular_Features
from ij.process import ImageConverter

def bubblesizer():

classifer_path = "D:\\Bubbles.model"

# Gets the image you want to segment.
your_image = IJ.getFilePath("Select image for WEKA segmentation")
target = IJ.openImage(your_image)

#launches weka segmentation.
weka = WekaSegmentation()
weka.setTrainingImage(target)

# Loads the classifier you have trained manually.
weka.applyClassifier(False)

# Shows you the segmented image.
segmentation = weka.getClassifiedImage()
segmentation.show()

# Converts to binary, runs watershed segmentation and analyze particles. Outputs area measurements.
ImageConverter(segmentation).convertToGray8()

WindowManager.getCurrentImage()
IJ.run("Make Binary")
IJ.run("Invert")
IJ.run(segmentation, "Watershed Irregular Features", "erosion=1 convexity_treshold=0 separator_size=0-200")
IJ.run("Analyze Particles...", "size=50-Infinity circularity=0.1-1.00 show=Outlines display summarize")

bubblesizer()
``````

And this is the result, which I think is more accurate as the other methods created too much space between bubbles. Not all bubles are segmented but it doesnâ€™t really matter, you want total area. By this logic maybe the watershed is redundant, up to you. Oh, and you may need to add the biovoxxel update site to get the watershed irregular features plugin.

How to count number of neuronal cells in fluorescence staining
#19

Is it possible to have the size of every individual bubble and export the results?

#20

Good day,

the various selections that result from â€śAnalyze Particlesâ€¦â€ť are stored in the â€śRoi Managerâ€ť and you may measure them together or in isolation. If you choose â€śAreaâ€ť and â€śArea fractionâ€ť in â€śSet Measurementâ€¦â€ť you will get the desired values.

Beacuse this is an elementary question concerning ImageJ, I recommend to thoroughly study the User Guide:
https://imagej.nih.gov/ij/docs/guide/index.html

Regards

Herbie