How to get a deformable mesh from this binarized image?

This question is linked to previous question but significantly different:

I am using Mathematica 10.2. I have a binarized image (see below) and wish to get a deformable mesh from it where I can add lines, delete lines or move nodes that are connecting edges (see the bottom most image). The point is to discretize the white lines into segments (mesh white lines in a way) that can be moved, removed or edited so as to ensure edge correction while not affecting the overall topology. Is that even possible? Any strategy or solution will be appreciated.

Same image as above but with the alterations that I wish to possibly make. • even if it is not deformable, what would be a convenient way to add or delete edges? Oct 18 '16 at 11:27
• Can you use Mathematica's drawing tools to manually draw on the image and erase lines (not sure if you can do this to only erase the white lines without erasing the black background)? Oct 21 '16 at 18:57

UPDATE 2

As I found in this answer, using MorphologicalTransform instead of ImageFilter gives performance gain and also works correctly in latest versions of Mathematica.

Also it is worth to note that the method suggested in the previous section gives false operations in situations like this (note the central part of the image):

img = Import["http://i.stack.imgur.com/2a2j6.png"];

Image[#, Magnification -> 8] & /@ {i = ImageTake[img, {493, 505}, {10, 20}],
MorphologicalTransform[i, If[#[[2, 2]] == 1 && Total[#, 2] == 3, 1, 0] &]} This problem can be solved by applying Thinning first:

Image[#, Magnification -> 8] & /@ {i = Thinning@ImageTake[img, {493, 505}, {10, 20}],
MorphologicalTransform[i, If[#[[2, 2]] == 1 && Total[#, 2] == 3, 1, 0] &]} Also (if desirable) it is possible to avoid removal of the end points by slight modification of the filtering function:

Image[#, Magnification -> 8] & /@ {i = Thinning@ImageTake[img, {493, 505}, {10, 20}],
MorphologicalTransform[i, If[#[[2, 2]] == 1 && Total[#, 2] <= 3, 1, 0] &]} UPDATE

The method of deleting the branch points in the original answer was quite crude, here is correct and more efficient approach based on ImageFilter. Unfortunately it doesn't work in the most recent versions of Mathematica due to a bug introduced in version 9. But with version 8.0.4 it works nicely:

img = Pruning[Thinning[Binarize@ImageCrop@Import["http://i.stack.imgur.com/qYhEr.png"]],
1];
img2 = ImageFilter[If[#[[2, 2]] == 1 && Total[#, 2] == 3, 1, 0] &, img, 1];
edges = MorphologicalComponents[img2];
edges // Colorize Here is a workaround which allows to use this method with recent (buggy) versions of ImageFilter:

img2 = ImageFilter[If[#[[3, 3]] == 1 && Total[#[[2 ;; -2, 2 ;; -2]], 2] == 3, 1, 0] &, img, 2]

(Not a complete answer but it could be a start.)

Here is how I would approach such a task. I'll show only an interactive approach for deleting and adding edges, but it can be extended for deformation of the edges (requires more work though).

First of all, I find the branch points:

img = Pruning[Thinning[Binarize@ImageCrop@Import["http://i.stack.imgur.com/qYhEr.png"]],
1];
branchPoints =
ImageValuePositions[MorphologicalTransform[img, "SkeletonBranchPoints"], White];

Now I delete them from the image and highlight the edges:

img2 = HighlightImage[img, {Opacity, Black, Disk[#, 1.6] & /@ branchPoints}];
edges = MorphologicalComponents[img2];
edges // Colorize Then I transform it into a Graphics object:

Graphics[GeometricTransformation[{RandomColor[], Point[Position[edges, #]]} & /@
Range[Max[edges]], {{0, 1}, {-1, 0}}], ImageSize -> 800] I can easily select any edge by double-clicking on it: ... and then delete it by pressing Del: Then it is easy to get the indices of the remaining edges back: You also can draw new edges using the Freehand line tool of the Drawing Tools palette: The line drawn can be extracted by applying Cases[#, edge_Line :> First@edge, Infinity] & (but be aware that you'll need to convert obtained coordinates into indices using the inverse of the GeometricTransformation used above): Of course this approach can be extended further using Dynamic functionality which allows interactive manipulations with the data.

• Thanks a lot. I have it working for the moment without the deformation though (which is extraneous if addition and deletion works). but once i am done implementing a Controls object (GUI) for my approach, I will definitely extend yours. Its wonderful so many thanks! Btw currently i am having trouble with implementing Controls since its my first time implementing a GUI so would really appreciate your help if you are interested and have time. Oct 23 '16 at 18:02
• @AliHashmi I'm glad it helps you. I've updated the answer with a simple edge drawing method based on the Drawing Tools palette. Oct 23 '16 at 18:19
• interesting. have to read up a little bit on these functions. But appears that they do the job :) Oct 23 '16 at 18:31
• @AliHashmi I've updated the answer with better method of deleting the branch points. At the bottom of the update I give a workaround allowing to use this method with the recent (buggy) version of ImageFilter. Oct 23 '16 at 21:14
• i just posted a new question. would be great if you can provide me some feedback : mathematica.stackexchange.com/questions/147943/… Jun 8 '17 at 22:41

I thought about a scheme to perform two most important operations on the image mask i.e. delete edges (in over-segmented regions or incorrect edges) or add edges (in under-segmented regions) with a list of specified points. Addition of Edge Scheme (through interpolation)

lets select some points on the boundaries for adding edges

seq = {{"555", "170"}, {"554", "157"}, {"554", "146"}, {"554",
"132"}, {"546", "123"}, {"535", "117"}, {"527", "104"}, {"525",
"95"}, {"521", "88"}, {"520", "82"}, {"513", "81"}};

interpPoints[selectedpts_, interpthresh_] := Module[{pts = selectedpts,
ptsToChange, positionReversal,reverselist, xrange, yrange, xs, ys, ascendListOrder,
interpolatedList, threshold = interpthresh},

pts = Map[FromDigits, pts, {2}];
pts = Partition[pts, 2, 1];
positionReversal = Position[pts, {{x_, _}, {x_, _}}];
reverselist = pts /. t : {{x_, _}, {x_, _}} :> Reverse /@ t;
ascendListOrder = Map[SortBy[#, First] &, reverselist];

interpolatedList = Map[Function[{x},
xs = x[[All, 1]];
ys = x[[All, 2]];

xrange = Range[Sequence @@ xs, threshold];
yrange = Subdivide[Sequence @@ ys, Length[xrange] - 1];
], ascendListOrder] // Round;

Flatten[MapAt[Map[Reverse, #] &, interpolatedList, positionReversal], 1]
]

now applying our construct:

pts = Map[FromDigits, seq, {2}];

ReplacePixelValue[imgmask, interpPoints[seq, 0.07] -> 1] //
Thinning // DeleteSmallComponents}, ImageSize -> Full] Delete edges scheme

lets select some points on the boundaries for removing edges

selectedpts = {{"654", "564"}, {"690", "563"}, {"775", "341"}, {"678",
"474"}, {"714", "485"}};

deleteEdgeSegments[imagemask_, selectedpts_,color_: RGBColor[0.2, 0.5, 0.9]] := 