# Measuring curve length on a binarized image

With the help of almighty Mathematica 9, I got from this

To this:

with this code:

MorphologicalBinarize[
Import["http://i.stack.imgur.com/79l19.jpg"]~
ColorConvert~"Grayscale"];
Binarize[LaplacianGaussianFilter[%, 10]];
CommonestFilter[MaxFilter[DeleteSmallComponents[%], 2.3], 10];
SelectComponents[MorphologicalComponents[%], "Length", -1] // Image;


I'm sure the code could be shorter and is perhaps in places redundant, but that's not why I'm posting here, as because now, I'm interested in measuring the length of the curve that I got.

I wanted to create a tool to test this theory whenever would I want so.

I couldn't find a way - I thought I was close when I transposed ImageData position on ListPlot, alas, I swiftly got lost there. I am very new to this wonderful tool and am learning it by trial and error.

I'd appreciate any form of help.

-
Did you see ComponentMeasurements[im, "PerimeterLength"] ? –  s.s.o Apr 18 at 8:25
Wow, I missed "Perimeter" section completely. This is it then. But, should I divide it by 2 since it's a perimeter? I mean, is it summed along each side of the curve? And If you're up for it, post it as an answer, I'll accept gladly. –  iccthedral Apr 18 at 8:33
The documentation states PerimeterLength is the "total length of outer pixel sides" while PolygonalLength is the "total length of the polygon formed by the centers of the perimeter elements." I wonder if the latter is what you are looking for. –  bobthechemist Apr 18 at 14:24
closely related –  Kuba Apr 18 at 20:28

There are a lot of measures in ComponentMeasurements. To find the correct one, you can easily create some test images:

i1 = Image[Table[Boole[i == 10], {i, 20}, {j, 20}], "Bit"]
i2 = Image[Table[Boole[i == j], {i, 20}, {j, 20}], "Bit"]


In the first one, we have 20 pixel in a row. Usually, you measure only the distance from pixel to pixel which leaves us with 19 straight (not diagonal) gaps between the 20 pixel. Therefore, the length should be 19.

In the second case, we have a diagonal setting where the space between each pixel is $\sqrt 2$. Therefore, its length should be $$19\cdot \sqrt 2 = 26.87$$

As bobthechemist correctly objected, "PolygonalLength" is the right measure:

ComponentMeasurements[#, "PolygonalLength"] & /@ {i1, i2}
(* {{1 -> 19.}, {1 -> 26.8701}} *)

-
This is probably the best built-in solution, but it's worth mentioning that it always overestimates the length of lines that are not perfectly axis-aligned or diagonal (by up to $8.2\%$). –  Rahul Narain Apr 18 at 22:55
I did a little Googling and this blog post is highly relevant: Measuring boundary length. It would be nice if Mathematica implemented this approach natively. You cannot even converge to $\pi$ using rasterized circles with Mathematica's current implementation :) –  Rahul Narain Apr 18 at 23:08
Wonderful, this is it. Thank you very much halirutan. –  iccthedral Apr 19 at 19:35

Another way to answer this is directly in terms of the white curve: you have a nice binary image and the length of the curve is the number of white pixels. This can be easily calculated:

img=Import["http://i.stack.imgur.com/rwDwl.png"]
Length@Select[Flatten@ImageData[img], # > 0.9 &]


which tells you that the curve is 1563 pixels long. As rasher points out, this same calculation can be done far faster (and with less typing) with:

Total[ImageData[img], 2]

-
Total[ImageData[img], 2], about 150X faster. –  rasher Apr 18 at 22:11
But this gives the length of the diagonal line in @halirutan's answer to be 19. –  Rahul Narain Apr 18 at 22:48
This isn't a general solution to the problem... but the number of pixels in the curve is plausibly analogous its length! –  bill s Apr 18 at 23:19
Unfortunately, the number of pixel is not comparable to the length of the curve. When you really have to measure something and you cannot be sure whether your measure is up to sqrt[2] off the correct length, then you shouldn't use it. The number of pixel is equal to the area of an object. –  halirutan Apr 19 at 20:10
@halirutan -- the question is about the "length of the river" in the image. Is there any reason to believe this is more like the geometric length than the pixel-length? –  bill s Apr 19 at 22:25