Group Abstract Group Abstract

Message Boards Message Boards

1
|
10.1K Views
|
4 Replies
|
5 Total Likes
View groups...
Share
Share this post:

How to get the perimeter of an image structure correctly?

Dear all,

I would need the perimeter of structures in images very precisely. So I started by doing some simple test:

enter image description here

Here is the above code:

img = ColorNegate@ColorConvert[Image@Graphics[Disk[]], "Grayscale"]
ImageDimensions[img]
ComponentMeasurements[img, #] & /@ {"Length", "Width"}
diameter = (1 /. ComponentMeasurements[img, "PolygonalLength"])/Pi

While "Length" and "Width" do make sense with reference to ImageDimensions the calculated diameter (by using the perimeter) is just wrong! Or am I making a stupid mistake?

Many thanks and best regards -- Henrik

POSTED BY: Henrik Schachner
4 Replies

Interesting. It looks like the radius computed from the polygon perimeter is the Authalic Radius, which is counting the length of the sides of the pixels that form the boundary.

In[89]:= (1 /. ComponentMeasurements[img, "AuthalicRadius"])*2

Out[89]= 363.41

If you compute the diameter instead based on the ConvexPerimeterLength, it gets a bit closer to the measurements given by the Length and Width properties that describe the best-fit ellipse. The points along the convex hull don't hug the pixel elements closely and look a bit closer to what you'd expect of a circle-like polygon around the component.

In[88]:= (1 /. ComponentMeasurements[img, "ConvexPerimeterLength"])/Pi

Out[88]= 346.648

You can see the difference between the polygon perimeter and the convex perimeter if you use a smaller circle and plot the points along the boundary. In the example here, the blue points are the perimeter positions of the boundary pixels, while the orange points are the vertices of the convex hull.

img = ColorNegate@ColorConvert[Image@Graphics[Disk[], ImageSize -> {50, 50}], "Grayscale"];
ListLinePlot[{(1 /. ComponentMeasurements[img, "PerimeterPositions"])[[1]], 
              (1 /. ComponentMeasurements[img, "ConvexVertices"])}, 
             PlotRange -> All, Joined -> False]

Boundary points

Interestingly, computing the area and deriving the diameter from that gets closest to the ellipse parameters computed by Length and Width.

In[15]:= Sqrt[(1 /. ComponentMeasurements[img, "Area"])/Pi]*2

Out[15]= 345.658

In[13]:= ComponentMeasurements[img, #] & /@ {"Length", "Width"}

Out[13]= {{1 -> 345.63}, {1 -> 345.502}}

Unfortunately, the convex perimeter isn't going to help you if you are looking to calculate the perimeter of a non-convex object in the image. You might be stuck with the PerimeterLength measurement for those kinds of shapes.

POSTED BY: Matthew Sottile
POSTED BY: Henrik Schachner

Hi Giulio,

many thanks for your detailed clarification! In this case I definitely prefer to see that the mistake is on my side - otherwise it would have been too stupid! I do read the documentation carefully, but I envisioned that a "polygon formed by the centers of the perimeter elements" would be something like a smooth curve or at least some approximation - in contrast to "PerimeterLength" as "total length of outer pixel sides". And on my machine here (v. 11.1.1) there is no ComponentMeasurements[_, "PerimeterPositions"], which would have helped.

Again many thanks and best regards -- Henrik

POSTED BY: Henrik Schachner
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard