I have hundreds of images similar to this image:
I'm looking to count the number of ellipses as well as their major and minor diameters. The ellipses are touching, hence,
img = Import["http://i.imgur.com/oNrJq0j.png"]
EdgeDetect[img]
doesn't return fillable ellipses so using something like
WatershedComponents[%]
returns useless information.
I'm very new to this type of image analysis using Mathematica so any help would be greatly appreciated.
Answer
One standard way to detect circular shapes is to binarize the image and apply a distance transform: The maxima locations of the distance transform are the centers of the circles.
To make this work on your ellipses, I first have to stretch them to be (roughly) circular, as @Rahul Narain suggested in a comment:
img = ColorConvert[Import["http://i.imgur.com/oNrJq0j.png"],
"Grayscale"]
{w, h} = ImageDimensions[img];
ir = ImageResize[img, {w/5, h*5}]
stretched = ImageRotate[ImageResize[img, {w/5, h*5}], 90 \[Degree]]
(The rotation is just for display. If I don't rotate the image by 90°, this post will be very long. It has no influence on the ellipse detection.)
Calculating the distance transform and finding the maxima is easy:
distTransform = DistanceTransform[Binarize[stretched]];
maxima = MaxDetect[distTransform, 2];
Here's a display of the result so far:
Grid[
Transpose[{
{"Stretched", "Binarized", "Distance Transform",
"Distance Transform Maxima"},
Image[#, ImageSize -> All] & /@ {
stretched,
Binarize[stretched],
ImageAdjust[distTransform],
HighlightImage[stretched, maxima]}
}]]
Now I can use ComponentMeasuements
to find connected maxima locations, their orientation, shape and the max. value in the distance transform image:
components =
ComponentMeasurements[{MorphologicalComponents[maxima],
distTransform}, {"Centroid", "SemiAxes", "Orientation", "Max"}];
Show[stretched, Graphics[
{
Red,
components[[All, 2]] /.
{
{centroid_, semiAxes_, orientation_, maxR_} :>
Rotate[Circle[
centroid, {maxR*Sqrt[semiAxes[[1]]/semiAxes[[2]]], maxR}],
orientation, centroid]
}
}]]
As you can see:
- the centroids are quite good, except for the ellipses near the border, because the border changes the distance transform
- the minor radius of the ellipses is ok (it's just the distance from the center to the nearest background point)
- the estimated orientation is ok,
- but the semi-axis length ratio of the maximum is only a rough estimate.
- You could probably apply smoothing before binarizing, use
MorphologicalBinarize
and hand-tune the filter/binarization parameters to improve the result
ADD:
I can improve the shape estimate a bit further using WatershedComponents
, with the distance transform maxima as seed points:
watershedComponents =
WatershedComponents[ColorNegate[distTransform], maxima] *
ImageData[Binarize[stretched]];
Colorize[watershedComponents]
Estimated Ellipses:
components =
ComponentMeasurements[
watershedComponents, {"Centroid", "SemiAxes", "Orientation"}];
Show[stretched, Graphics[
{
Red,
components /.
{
(n_ -> {centroid_, semiAxes_, orientation_}) :>
{
Rotate[Circle[centroid, semiAxes], orientation, centroid],
Text[n, centroid]
}
}
}]]
Comments
Post a Comment