How to separate paths from the output of EdgeDetect?



I have been trying to find a way to separate the various closed paths that can be output by EdgeDetect. For example, taking the output of:

ColorNegate@EdgeDetect@Graphics[Style[Text["8"], 400]]

enter image description here

I'd like to be able to obtain a list like:

enter image description here

I'd really love to show some progress I made on this, but to be honest, I'm stuck at the beginning. I really don't know how to attack this one. The naïve approach might be to take one black pixel, then go around it registering adjacent pixels as part of the same path, while erasing them from the original image. But I don't expect this to be anything other than painfully slow, and there probably are some Mathematica image manipulation functions that I could leverage. So, how would you advise me to start?


Posted 2012-04-14T13:51:54.057

Reputation: 10 517


@ F'x This question seems very close to this one: Perhaps the same method would work.

– R Hall – 2012-04-14T15:52:09.993



You can use MorphologicalComponents to get the different loops:

With[{components = MorphologicalComponents@EdgeDetect@Graphics[Style[Text["8"], 400]]},
    ColorNegate@Image[1 - Unitize[components - #]] & /@ Range[Max[components]]]

enter image description here

Trying this on other similar characters — {"A", "B", "g", "9"}

enter image description here

rm -rf

Posted 2012-04-14T13:51:54.057

Reputation: 85 395


This is partly derived from Vitaliy answer here.

pic = 
     Rasterize[Style["8", FontFamily -> "Times"], ImageSize -> 500] //
       Image, 1]];
pdata = Position[ImageData[pic, DataReversed -> True]\[Transpose], 1];
lcp = ListCurvePathPlot[pdata, Axes -> None]

My only change is the massaging to get the '8' upright.

Mathematica graphics

Now it's pretty easy to get the paths from it:

Graphics /@ Cases[lcp, Line[a_], Infinity]

Mathematica graphics

Sjoerd C. de Vries

Posted 2012-04-14T13:51:54.057

Reputation: 63 549


While R.M. and belisarius answers certainly work, they seem a bit complex for me, extracting separate masks out of MorphologicalComponents's output. It gets a lot simpler if you use ComponentMeasurements instead, which simply returns a list of masks for each component (as sparse arrays, so might be more efficient, too):

edges = EdgeDetect@Graphics[Style[Text["8"], 400]]; (* taken from belisarius's answer *)
masks = ComponentMeasurements[edges, "Mask"];
Image /@ masks[[All, 2]]

Niki Estner

Posted 2012-04-14T13:51:54.057

Reputation: 34 978


In the same spirit as RM's answer

mc = MorphologicalComponents[EdgeDetect@Graphics[Style[Text["8"], 400]]];
Image /@ (Array[Replace[mc, {{Except[#] -> 0}}, {2}] &, Max@mc][[All, 1]])

enter image description here

Dr. belisarius

Posted 2012-04-14T13:51:54.057

Reputation: 112 848