0

Is there any way to convert or merge sets of points (which obviously look like curves just with gaps) into continuous smooth curves so they could be defined by a path or continuous contour (and later saved as vector path in SVG file)? Is there any library in Python that deals with such things?

It is the result of cv2.findContour(...): contours

It has returned ~800 contours whereas it seems that all of them could be merged into a smooth 25-30 contours.

Small details are important therefore I cannot use simple blur with threshold before cv2.findContour() on the image to get smooth contours from the beginning.

I tried to use scypi.interpolate.* lib to build a smooth curve from a set of points, but the problem is that I cannot determine a subset of contours that to merge prior to interpolation.

Greg
  • 137
  • 2
  • 11
  • This looks like a classic "findContours before you finished cleaning up your input image", so: "result of cv2.findContour(...)" on what input, and is that input just "an image" or did you remember to `cv2.threshold` it first? Also, have you looked at other SO questions about fitting curves to numpy contours, like https://stackoverflow.com/questions/47936474 and searched the web for tutorials on curve fitting specifically when using numpy contours? (If so, please mention [all your research so far in your post, too](/help/how-to-ask)) – Mike 'Pomax' Kamermans Sep 14 '21 at 15:27
  • It's not the "salt-and-pepper removal" problem. Sure, I do "cv2.threshold()" prior to contour detection to remove noise (the result depicted above came after all those preparations). The issue is to merge broken lines (contours) so they give bigger contours. The closes topic is discussed here https://stackoverflow.com/questions/43293915/how-could-i-make-the-discontinuous-contour-of-an-image-consistant/43384849, yet it's about using ImageMagick which is not an option for me. – Greg Sep 14 '21 at 18:11
  • Please remember to mention that in your post, too, because folks who leave a comment are often not the same people as those who write an answer. Make sure people don't need to read the comments just to get all the details. – Mike 'Pomax' Kamermans Sep 14 '21 at 21:12
  • Also I would still recommend showing more code here, as well as your image input. Show the image you start with, and the [mcve] code that you wrote to get from that to the contour image, so that there's more for people to comment on. If you have questions about code, always [try to show the relevant code](/help/how-to-ask). The shorter the code, the better, as long as it's MCVE enough to allow folks to go "hm, let's see yep, that reproduces the post's claims, let me edit this code until it does what they need". – Mike 'Pomax' Kamermans Sep 16 '21 at 15:11

1 Answers1

0

I think morphological operations is the answer here. Try this:

import cv2

image = cv2.imread("path/to/image")
cv2.imshow("image", image)
cv2.waitKey(0)


kernel = np.ones((3, 3),np.uint8)
dilated_image = cv2.dilate(image, kernel, iterations = 1)
cv2.imshow("dilated_image", dilated_image)
cv2.waitKey(0)
eroded_image = cv2.erode(dilated_image, kernel, iterations = 1)
cv2.imshow("eroded_image", eroded_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

And you get this: enter image description here

Performing erosion after dilation is called closing. It can also be performed as

closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)

You can manipulate the kernel size, number of iterations, and kernel pattern to obtain the desired results.

fam
  • 583
  • 3
  • 14
  • Thanks for the answer, but, unfortunately, they don't. After dilate() the image loses all small details (stand-alone contours with 3-4 points) that are important. I need to keep as much of the original image as possible especially the thickness of the lines. – Greg Sep 14 '21 at 13:51
  • Reduce the number of iterations to `1` and choose a kernel of size `3x3`. – fam Sep 14 '21 at 13:53