I have a *.bmp image, e.g. this one:

enter image description here

I need to smooth boundaries of the thick curves and save it in a vector graphics form. Is there a simple way how to do that in Mathematica 10? I know it is probably an easy task, but can't figure it out. Thank you.

  • $\begingroup$ "save it in a vector graphics form" - ImageMesh[ColorNegate[image]] would be a good start. $\endgroup$ – J. M.'s discontentment Apr 3 '17 at 8:45
  • $\begingroup$ I'm sorry, I forgot to mention that I have a version 10. $\endgroup$ – T. Rihacek Apr 3 '17 at 8:52
  • 1
    $\begingroup$ It is actually Binarized@ArrayPlot + 2 horizontal lines. You are right, I would like to have curves with smooth boundaries and the lines across them, with sharp corners in intersection. $\endgroup$ – T. Rihacek Apr 3 '17 at 12:16
  • 1
    $\begingroup$ Without such a requirement I would suggest double Blur as the first step: Binarize[Blur[Blur[i, 6], 6], .5]. That would be easy but with the additional requirement the problem becomes tricky. $\endgroup$ – Alexey Popkov Apr 3 '17 at 15:58
  • 1
    $\begingroup$ Have you seen vectormagic.com ? $\endgroup$ – Mr.Wizard Apr 5 '17 at 7:01

I would like to have curves with smooth boundaries and the lines across them, with sharp corners in intersection.

Part 1: isolate the boundaries

Import the image and remove the frame:

img = Import["https://i.stack.imgur.com/SJwTu.png"];
img1 = ImagePad[img, -4]


Remove the white borders excepting the left border (we'll need it at the next steps):

border = BorderDimensions[ImageTake[img1, 20]];
img2 = ImagePad[img1, -border + {{4, 0}, {0, 0}}]


Find positions of the pixels of the horizontal lines and make them white:

horizontalLinesPos = {All, #2} & @@@ PixelValuePositions[ImageTake[img2, All, 1], 0];
img3 = ReplacePixelValue[img2, horizontalLinesPos -> 1]


Find internal perimeters of the black components:

img4 = MorphologicalTransform[ColorNegate@img3, "Remove"]


At this step we get a problem. We have to decide what to do with the horizontal "tails" like this:

ArrayPlot[1 - ImageData[ImageTake[img4, {51, 67}, {334, 351}]], Mesh -> True, 
 ImageSize -> 400]


Since such "tails" correspond to actual data points (represented as black pixels on the original image), it is reasonable to keep them.

Now we have to remove the horizontal and vertical borders excepting at the left where the vertical border actually is a continuation of the curve. And we have to keep the "tails" at the same time. For this purpose it is better to start again from the img2:

img3 = MorphologicalTransform[ColorNegate@img2, "Remove", Padding -> 1];
img4 = ReplacePixelValue[img3, horizontalLinesPos -> 0]


Part 2: extract the curves

masks = ComponentMeasurements[img4, "Mask"];

curves = Transpose[Reverse@#]["NonzeroPositions"] & /@ masks[[;; , 2]];

horLines = Join[{∞}, Mean /@ Split[horizontalLinesPos[[;; , 2]], Abs[#1 - #2] == 1 &], {0}]
{∞, 508, 342, 175, 0}
dataLines = 
   Flatten[#, 1] & /@ 
      Table[Select[curves, horLines[[i]] > Min[#[[;; , 2]]] > horLines[[i + 1]] &], 
        {i, Length[horLines] - 1}], Automatic, Missing[]]], {Missing[], Missing[]}, {2}];



Part 3: smooth the curves

There are infinitely many possible ways to perform the smoothing. For recovering the original data points the approach shown by nikie in this answer seems the most appropriate. If the goal is just to obtain smoothed boundaries, one can use approaches shown in this thread.

| improve this answer | |

The smoothing of the edges can be accomplished using one of the edge-preserving smoothing functions. For example, the PeronaMakil filter gives:

img = ImagePad[Import["https://i.stack.imgur.com/SJwTu.png"], -4];
edges = EdgeDetect[PeronaMalikFilter[img, 20, 100]]

enter image description here

Another similar filter is the CurvatureFlowFilter.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.