# Finding the area, algebraic curve and jaggedness of an arbitrary shape

I start with a photograph of a shape (physically made by the flow of a liquid into another), of which I can extract the border, manually or using Mathematica's feature detect feature :

Using the method described here, I extract some points of the shape, in a standard list form ({{x,y},{x,y}, ...}). Here is the example plot of such data :

How to :

1. Obtain the shape's area (area of the enclosed zone)
2. How to get an algebraic fit of the shape (and/or part of it)?
3. How to compare one shape against another, on their respective "jaggedness".

Question 3 is more of a mathematical question, but I'm just searching for an approximate comparison tool, more in the spirit of the following example than something absolute:

I expected CornerFilter to work, but it seems to give no result whatsoever. As for 2, I can fit small part of the curve using Fit[], but the general shape has multiple point with the same x, which forbid this.

-
For the first: here's a short routine for computing the signed area, assuming your points have already been ordered either clockwise or anticlockwise: PolygonSignedArea[pts_?MatrixQ] := Total[Det /@ Partition[pts, 2, 1, {1, 1}]]/2. If the points aren't already sorted, Sjoerd says to look at ListCurvePathPlot[] (and the related function FindCurvePath[]). –  Guess who it is. May 22 '12 at 18:58
For "respective jaggedness" you could use Box Counting method used on fractal shapes: this en.wikipedia.org/wiki/Box_counting or this en.wikipedia.org/wiki/Fractal_dimension_on_networks –  Vitaliy Kaurov May 22 '12 at 19:35
@J.M. are you sure your routine sorts them anticlockwise (or clockwise)? Also, even if you sort by the polar angle, that does not guarantee that a ray coming out of the centre of the shape will not intersect it twice. –  acl May 22 '12 at 19:46
@acl: hmm, yes; that is indeed a caveat of sorting by polar angle. I don't have a better approach at the moment. –  Guess who it is. May 22 '12 at 19:49
Could you tell us your requirements regarding your "algebraic fit"? –  Sjoerd C. de Vries May 22 '12 at 20:20

You can use Mathematica's image processing functions for questions 1 and 3. Here's how:

### 1: Area

img = Binarize@Import["http://i.stack.imgur.com/I2gkK.jpg"] ~Erosion~ 1;
(m = MorphologicalComponents[img]) // Colorize


To get the area of the pink part in sq. pixels, use ComponentMeasurements:

2 /. ComponentMeasurements[{m, img}, "Area"]
(* 25168.1 *)


### 3: Jaggedness

Given two shapes with a similar area, the more jagged one will have a larger perimeter. So a simple way to approximate "jaggedness" would be to use the same function, ComponentMeasurements and compare the perimeters (provided the areas are similar)

2 /. ComponentMeasurements[{m, img}, "PerimeterLength"]
(* 1352 *)


If the areas are not the same, you could find the "EquivalentDiskRadius" (which gives you the radius of the circle with the same area as the shape) for each shape and see by what percentage the corresponding perimeter lengths are off from that of the respective circles.

-
+1, though I'm not sure about "Given two shapes with a similar area, the more jagged one will have a larger perimeter." What about two rectangles with the same area but different circumference? Intuitively I'd say both have the same jaggedness. –  Sjoerd C. de Vries May 22 '12 at 20:55
@SjoerdC.deVries I see your point. I took the spirit of the question to be along the lines of "Here's this irregular blob and here's another irregular blob. How can I tell which is approximately smoother, for some definition of 'smooth'." –  The Toad May 22 '12 at 21:01
+1, and I think ComponentMeasurements can answer question 2, too, with the Length/Width/SemiAxis/Orientation/Elongation/Eccentricity measurements –  nikie May 23 '12 at 9:23

For computing the area of a non-intersecting polygon, I propose:

polyarea =
Compile[{{v, _Real, 2}},
Block[{x, y},
{x, y} = Transpose[v];
Abs[x.RotateLeft[y] - RotateLeft[x].y]/2
]
]


Example:

Needs["ComputationalGeometry"]
poly = #[[ConvexHull @ #]] & @ RandomReal[100, {15, 2}];

Graphics[Polygon @ poly]

polyarea @ poly


5429.68

-
The question wasn't about polygons, right? Because all three questions would be straightforward, if it were. Besides, I'd use GraphicsMeshPolygonArea@Polygon[poly] for the area... –  The Toad May 23 '12 at 17:05
@R.M I assumed that converting the shape to a polygon would be one avenue of approach. That function isn't in version 7; how does its performance compare to mine? –  Mr.Wizard May 23 '12 at 17:19
Hmm... I did not know it's not available in 7. They both give the exact same answer and are equally fast (also, it isn't necessary to wrap the points in Polygon` as I wrote above) –  The Toad May 23 '12 at 17:55