how to get a deformable mesh from this binarized image

This question is linked to previous question but significantly different:

how to get cell boundaries in the image

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?
– Ali Hashmi
Oct 18 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)?
– user13999
Oct 21 at 18:57

=================

2 Answers
2

=================

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]

Original answer

(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[1], 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.
– Ali Hashmi
2 days ago

  

 

@AliHashmi I’m glad it helps you. I’ve updated the answer with a simple edge drawing method based on the Drawing Tools palette.
– Alexey Popkov
2 days ago

  

 

interesting. have to read up a little bit on these functions. But appears that they do the job 🙂
– Ali Hashmi
2 days ago

  

 

@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.
– Alexey Popkov
2 days ago

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.

the image below is a mask which we save as imgmask

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];
ptsToChange = Thread@{xrange, yrange}
], ascendListOrder] // Round;

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

now applying our construct:

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

GraphicsRow[{imgmask, HighlightImage[imgmask, Point@pts],
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]] :=
Module[{pts = selectedpts, mask = imagemask },
pts = Map[FromDigits, pts, {2}];
GraphicsRow[{HighlightImage[mask, {color, AbsolutePointSize[10], Point@pts}],
mask = DeleteSmallComponents[ReplacePixelValue[mask, pts -> 0]]},ImageSize -> Full]
]

now applying our construct for deleting edges:

deleteEdgeSegments[imgmask, selectedpts]