4

I'm trying to separate the lines and circles, instead of lines some circles are connected with curves.

I tried to use contours to find circles but it is however including the lines inside the contour, so I also tried skeletoning the image so that to see if the connection between the circles and lines might break, but it is unsuccessful.

Hough_circles is not detecting circles in all cases, so the only option I've to find the circles using contours once the lines around it are eliminated.

Input Image

  • EDIT

Example 2

Input

Input Image

Output :  Not desired output

Output image

In the output image, I got circles weren't got separated and lines got merged with circles and the contour gave a different shape.

Please find some way to split the circles and lines. Please try to answer it in Python instead of C++. C++ answers are allowed too.

Thanks in advance!

Strange
  • 1,460
  • 1
  • 7
  • 18
  • Please read "How to Ask A Good Question" (https://stackoverflow.com/help/how-to-ask). Then edit your question and add the code you've tried so far. What happens when you run it? What did you expect to happen instead? Any errors? – fmw42 Jan 30 '20 at 17:23
  • I've posted the approaches i've tried, but i don't know proper procedure to achieve the goal, that's why i haven't posted any of the code i've done. I need an approach to achieve this, this is not error solving problem please read the question properly before you post a comment – Strange Jan 30 '20 at 20:03
  • You want to detect the three circles? – nathancy Jan 30 '20 at 20:43
  • `@Strange`. You said you used Hough Circles and it did not work. Post the full code so we can see what you might have done wrong and so we can test your code. – fmw42 Jan 30 '20 at 22:01
  • Why do you post the result of your initial attempt (contours), rather than the original image? It's possible that your first steps make the process harder. – Cris Luengo Feb 03 '20 at 08:33
  • Also, since the question has an accepted answer, you might not get a whole lot of attention any more. Either unaccept the answer or ask a new question. – Cris Luengo Feb 03 '20 at 08:34
  • I unaccepted the answer, by the way i've posted the original image in the first attempt, i've got the answer from the accepted answer, but it failed for image i've posted as an edit. Please try to find an approach. Hope you've understood the question. – Strange Feb 03 '20 at 09:27

1 Answers1

8

Here's a simple approach using morphological operations. The idea is to fill the contours, create an elliptical shaped structuring element, then morph open to remove the lines. From here we simply find the external contours and draw the circles. Here's the process visualized:

Filled thresholded image

enter image description here

Morph open

enter image description here

Result

enter image description here

Code

import cv2

# Load iamge, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Fill contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(thresh, [c], -1, (255,255,255), -1)

# Morph open
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)

# Draw circles
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.drawContours(image, [c], -1, (36,255,12), 3)

cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()

For the other image using contour hierarchy

enter image description here enter image description here enter image description here enter image description here

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Filter using contour hierarchy
cnts, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
hierarchy = hierarchy[0]
for component in zip(cnts, hierarchy):
    currentContour = component[0]
    currentHierarchy = component[1]
    x,y,w,h = cv2.boundingRect(currentContour)
    # Only select inner contours
    if currentHierarchy[3] > 0:
        cv2.drawContours(mask, [currentContour], -1, (255,255,255), -1)

# Filter contours on mask using contour approximation
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.05 * peri, True)
    if len(approx) > 5:
        cv2.drawContours(mask, [c], -1, (0,0,0), -1)
    else:
        cv2.drawContours(image, [c], -1, (36,255,12), 2)

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.imshow('mask', mask)
cv2.waitKey()

Note: For a through explanation on contour hierarchy, take a look at understanding contour hierarchy and retrieval modes

nathancy
  • 42,661
  • 14
  • 115
  • 137
  • You can go even further with nathancy's excellent answer by formally fitting to a circle. See https://stackoverflow.com/questions/55621959/opencv-fitting-a-single-circle-to-an-image-in-python – fmw42 Jan 30 '20 at 22:11
  • I tried to implement this approach in another image, but I got a problem. I've updated the question with new images which are the input and outputs after applying operations you've suggested. please check whether there is a way to separate circles in this example too. BTW see the question to see the examples I'm failed with. – Strange Feb 03 '20 at 08:01
  • I have a solution that works for the 2nd example using contour hierarchy but unfortunately it doesn't work with the 1st example. You can experiment with changing the kernel sizes and the number of iterations. good luck! – nathancy Feb 03 '20 at 21:33
  • could you please share the solution for the second example as an edit to your answer. Please it would help me. Actually i asked this question for the concern of 2nd example – Strange Feb 04 '20 at 14:45
  • @Strange I'm not sure how robust it is but there you go – nathancy Feb 05 '20 at 03:18
  • I didn't get the same output as you got for the second example using the answer provided using contour-hierarchy approach. – Strange Feb 05 '20 at 16:27
  • Weird, I added more output images for each step – nathancy Feb 05 '20 at 20:46