Finding ellipses with incomplete boundaries


I have a problem I was hoping I could get some help with :slight_smile:

I am working on an project where I analyse images so that I can find eggs of varying shape and size but that are generally elliptical. Isolated eggs have solid boundaries which are easy to find with imageJ. The problem is that the eggs will all be concentrated into a small region and overlaps with other eggs and with background debris will be inevitable. So there will be many cases in which these elliptical contours will be incomplete? Is there some way that imageJ can complete a contour with some gaps? Or perhaps someone has encountered this same problem before and has another solution?

Thanks in advance for your help :slight_smile:


Hello Luke,

Can you show an image so we all understand better your problem?


PS: In any case, you can always try the Ellipse fit plugin if you manage to binarize the images first.


Thanks Ignacio
Here is the binary version with the border of the cell isolated (sideways elongated U shape in in the centre of the image). As you can see the elipse perimeter is incomplete.

I will try the ellipse fitter plugin as you suggested
Thanks very much :slight_smile:


Hi @lukecoburn,
could you please give also the “raw” image before threshold?

I think that it is not easy at all to find ellipse in this case, I had read something about find ellipse and circles by Hough Transform but don’t know if it easy to implement and if it works properly with this kind of incomplete boundaries.
Maybe it could be useful to find a better way or some tricks to extract boundaries, that’s why I asked you the “raw” image.

I link you an article that seems good and a proposed implementation in matlab (not mine).

Have a nice day,
Emanuele Martini

1 Like

Apologies. Here is the image before thresholding.

Here is a macro which segments the eggs in that image:

path = "a25ba3df0bf703069179fa7fb8581ae882e30078.jpg";
open("/Users/curtis/Desktop/" + path);
run("Duplicate...", "title=background");
run("Gaussian Blur...", "sigma=100");
imageCalculator("Subtract create 32-bit", path,"background");
selectWindow("Result of " + path);
setAutoThreshold("Triangle dark");
run("Create Mask");
run("Fill Holes");
run("Analyze Particles...", "size=1000-100000 circularity=0.50-1.00 add");

And here is the result on the above image:

You can tune exactly which eggs are selected by editing the “1000-100000” size restriction in the Analyze Particles command.

That said, you’re right that sometimes, the fit won’t be so good. And in that case, the Fit Ellipse command mentioned by @iarganda is a good thing to try. But note that that command must be done on a per-selection basis, so once you get your ROIs in to the ROI Manager as done above, you would need to loop over them, and for each one, perform some “processing” of the selection to make it more accurate. One option would be to use Process :arrow_forward: Selection :arrow_forward: Enlarge… with a negative value like -20, followed by the same positive value of 20—this will “round off” the borders, prior to fitting the ellipse with Fit Ellipse.

Maybe something like this (only lightly tested):

roiCount = roiManager("count");
for (i=0; i<roiCount; i++) {
	roiManager("select", i);
	// round off the edges
	run("Enlarge...", "enlarge=-20");
	run("Enlarge...", "enlarge=20");
	// ensure the selection conforms to an ellipse
	run("Fit Ellipse");
	// add the updated ROI to the manager
	roiManager("add", i);
// delete the old ROIs
for (i=0; i<roiCount; i++) {
	roiManager("select", i);

See the Segmentation page for more general ideas about how to effectively identify and measure your objects. See Recorder for details on how I developed this macro easily. See Batch for info on how to automatically apply such workflows to a series of images.


Thanks very much for going to the trouble to produce this macro. The “egg” in this case is the lighter elongated rough ellipse in the centre. The features you have highlighted are air bubbles. Can you’re approach be altered somewhat so as to select the single particle in the middle?

As you point out, the eggs themselves sort of “fall off” on the right-hand side, making segmentation trickier. Even after correcting for uneven illumination, the thresholding still has some trouble. One idea I had was to start from my “eggs+bubbles” ROIs, and then do some kind of region growing from the center of each ROI to isolate the eggs only. But this is where my (lack of) expertise at image processing ends.

@iarganda @biovoxxel @imagejan @tibuch Any ideas?

Hi @lukecoburn, hi all,

I tried the following procedure which works fine for the provided image but without any guarantee that it will be transferable to other images. This finally depends on the variability in imaging quality and color composition of the image since the color threshold is quite limiting in the hue part.

To be able to run it you will need to activate the BioVoxxel update site since the macro uses 2 plugins from there.
If the egg sizes are very variable you might also need to adjust the size specifications during the particle analysis as well as the iterations for the erosion function. Otherwise you might accidentally lose the egg.

//lighting correction
original = getTitle();
run("Select None");
run("Pseudo flat field correction", "blurring=300");
close(original + "_background");

// Color Thresholder 2.0.0-rc-44/1.50e
// Autogenerated macro, single images only!
run("HSB Stack");
run("Convert Stack to Images");
for (i=0;i<3;i++){
  setThreshold(min[i], max[i]);
  run("Convert to Mask");
  if (filter[i]=="stop")  run("Invert");
imageCalculator("AND create", "0","1");
imageCalculator("AND create", "Result of 0","2");
for (i=0;i<3;i++){
selectWindow("Result of 0");
selectWindow("Result of Result of 0");
// Colour Thresholding-------------

//shape correction of egg (if egg sizes differ a lot, iterations might need adjustment)
run("EDM Binary Operations", "iterations=10 operation=close");
run("EDM Binary Operations", "iterations=45 operation=open");

//analysis and retrieval of ellipsoid ROI (min. size in Analyze Particles might need some adjustment)
run("Analyze Particles...", "size=20000-Infinity circularity=0.00-0.80 exclude add");
roiManager("Select", 0);
run("Fit Ellipse");
roiManager("Select", 0);



Hello @lukecoburn

I tried the following procedure in KNIME Image Processing:

  • Do a rough segmentation of the egg with a big gaussian convolution.
  • Filter Segments based on size and circularity
  • Find sharp label with otsu only applied to the rough segment area

This is the result:

And here is the (35.2 KB) workflow.


Wow, I totally misread this earlier. Only after seeing the segmentations produced by @biovoxxel and @tibuch did I understand what you meant. Sorry for the noise—never trust a computer scientist to do a biologist’s job I guess. :wink:


Hey @ctrueden,

Don’t worry. Without the further comment on the bubbles I also would have gone for the incorrect structures :grin:

1 Like

Thanks @ctrueden. Im sorry I wasn’t clear in my original email and your approach was actually really helpful. I hadn’t been removing the background properly before. I can really isolate the entire border of the egg with your approach so thanks :slight_smile:


sometimes some preprocessing of the image it could be easier than some real hard post processing analysis like try to fit and find ellipses with incomplete boundaries :wink:

Have a nice week,

1 Like

Just trying to reproduce this first macro for an upcoming workshop… I had some issues with reproducing the given snapshot of results. With some minor alterations - I was able to produce the same result. See amended code here:

path = "UnevenIllumination.jpg";
open("/Users/ellenarena/Documents/LOCI_docs/Workshops/SegmentationWithFiji_examples/" + path);
run("Duplicate...", "title=background");
run("Gaussian Blur...", "sigma=100");
imageCalculator("Subtract create 32-bit", path,"background");
selectWindow("Result of " + path);
setAutoThreshold("Triangle dark");
run("Create Mask");
run("Fill Holes");
run("Fill Holes");
run("Analyze Particles...", "size=100-100000 circularity=0.50-1.00 add");