pythonopencvimage-processingomr

Use OpenCV to identiy hollow and filled circles


I'm using OpenCV houghcircles to identify all the circles (both hollow and filled). Follow is my code:

import numpy as np
import cv2

img = cv2.imread('images/32x32.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

bilateral = cv2.bilateralFilter(gray,10,50,50)

minDist = 30
param1 = 30
param2 = 50
minRadius = 5
maxRadius = 100

circles = cv2.HoughCircles(bilateral, cv2.HOUGH_GRADIENT, 1, minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)

if circles is not None:
    circles = np.uint16(np.around(circles))
    for i in circles[0,:]:
        cv2.circle(img, (i[0], i[1]), i[2], (0, 0, 255), 2)

# Show result for testing:
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Test input image 1: enter image description here

Test output image1: enter image description here

As you can see I'm able identity most of the circles except for few. What am I missing here? I've tried varying the parameters but this is the best i could get.

Also, if I use even more compact circles the script does not identify any circles whatsoever.

enter image description here


Solution

  • An alternative idea is to use find contour method and chek whether the contour is a circle using appox as below.

    import cv2
    
    img = cv2.imread('32x32.png')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    inputImageCopy = img.copy()
    
    # Find the circle blobs on the binary mask:
    contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # Use a list to store the center and radius of the target circles:
    detectedCircles = []
    
    # Look for the outer contours:
    for i, c in enumerate(contours):
    
        # Approximate the contour to a circle:
        (x, y), radius = cv2.minEnclosingCircle(c)
    
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        
        if len(approx)>5: # check if the contour is circle
            
            # Compute the center and radius:
            center = (int(x), int(y))
            radius = int(radius)
    
            # Draw the circles:
            cv2.circle(inputImageCopy, center, radius, (0, 0, 255), 2)
    
            # Store the center and radius:
            detectedCircles.append([center, radius])
    
    cv2.imshow("Circles", inputImageCopy)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    

    enter image description here

    enter image description here