# extract line from position data

I got a picture like this, and what I want to do is to extract lines from the picture.

what I have done now is

img = Import["http://euler.nmt.edu/mathwiki/images/e/ef/Borromean.png"]
PixelValuePositions[img, Blue, 0.5] // Point // Graphics


from which I get a list of positions of the blue curve like this:

so my question is , how do I get a Line from the postion data I get above? what I want to get is not a circle function, but a list of points in good order.

• I'm not clear what you're asking - the result of PixelValuePositions is a list of positions of the "points".
– ciao
Mar 5 '14 at 9:19
• Vectorize the image first to PDF for example via online.rapidresizer.com, then import that to Mma.
– BoLe
Mar 5 '14 at 9:55
• @rasher,but with PixelValuePositions I get a list of unordering points, what I want is like this Line[{p1,p2...pn}] Mar 5 '14 at 10:34
• @tintin FindCurvePath can make the ordering.
– BoLe
Mar 5 '14 at 10:59

There are over 2700 points and because they fill out a thick region, there is no real order to them. It seems to me to get a single line, one would want to approximate the image by lines first. One way is to use Thinning.

img = Import["http://euler.nmt.edu/mathwiki/images/e/ef/Borromean.png"];
comp = MorphologicalComponents @ Thinning[ColorNegate @ Binarize[img]];
splice[{list1_?VectorQ, list2_?VectorQ}] /;
First@list1 == First@list2 := Join[Reverse@list1, Rest@list2];
splice[lists_] := Join @@ lists;

Graphics[
Table[
{Hue[c/6 - 0.1], With[{pos = Position[comp, c]},
Line[pos[[
splice @ FindCurvePath[pos]
]]]]},
{c, 6}]
]


Update: It happens in this case that FindCurvePath splits the first three lines into two components with the same starting point; the fourth into two disjoint components; and the rest are just one line. When I first posted, I had forgotten to check all of them. The update fixes how they are spliced together. Some smoothing may obtained by skipping some points:

splice[FindCurvePath[pos]] ~Part~ (3 ;; -3 ;; 3)


Another way is to fit a circle:

circle = FindFit[
Transpose[Append[Transpose[#], ConstantArray[0, Length @ #]]] &@
PixelValuePositions[img, Blue, 0.5], (x - a)^2 + (y - b)^2 - r^2,
{a, b, r}, {x, y}]
(*
{a -> 95.864, b -> 97.5503, r -> 89.9539}
*)

Graphics[{
PixelValuePositions[img, Blue, 0.5] // Point,
Red, Circle[{a, b}, r] /. circle
}]


One can use the circle data to generate a Line if desired.

There is also the methods found in Derive a smooth circle with cusp from an image

• thanks so much, the first part is exactly what I want Mar 5 '14 at 12:43
• @tintin You're welcome and thanks for the accept. You might be interested the modification I made, which I think is an improvement. Mar 5 '14 at 13:42
• nice answer, nice update, it works Mar 5 '14 at 16:04

Without going to morphological manipulations, a quick way that might get you what you need (it's not super clear in the op) might be (uses the second image in your question in img2):

Needs["ComputationalGeometry"]
pp = PixelValuePositions[img2, Black, 0.5];
curvelines = pp[[ConvexHull[pp, AllPoints -> True]]];
Graphics[{Line[curvelines]}]
`