pythonopencvcomputer-visionobject-detectionhough-transform

Circle detection on craters by Hough OpenCV - Python


I am trying to detect the circles on some lunar craters images. Here are some examples:

Example 1 Example 2 Example 3

After binarization, closing operation and removing noise, I ended up with such results:

Example 1 - effect Example 2 - effect Example 3 - effect

I am now trying to fit the circles to the binarized images. I've decided to use OpenCV and HoughCircles() method. I've found a very simple example on the official OpenCV website, so I've used it in my code:

import numpy as np
import cv2 as cv

img = cv.imread('binarized_image.jpg', cv.IMREAD_GRAYSCALE) #read the image
assert img is not None, "file could not be read, check with os.path.exists()" #check if file exists

img = cv.medianBlur(img,5)
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
                            param1=30,param2=15,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv.imshow('detected circles',cimg)
cv.waitKey(0)
cv.destroyAllWindows()

However, I am constantly ending up with error:

AttributeError: 'NoneType' object has no attribute 'rint'

It's the effect of line with circles = np.uint16(np.around(circles)). It basically means, that my code did not detect ANY circles in the image. I've tried to modify param1 and param2 in the cv.HoughCircles but none of the values seems to work. The results that I expect should be something like this:

Example 1 detection Example 2 detection Example 3 detection

How can I achieve this and detect the circles? How should I modify my code?


Solution

  • Your code works fine for me on Mac OSX Ventura. Note that I have added a line for cv.imwrite() to save the result to disk to show you.

    Input:

    enter image description here

    import numpy as np
    import cv2 as cv
    
    img = cv.imread('binarized_image.jpg', cv.IMREAD_GRAYSCALE) #read the image
    assert img is not None, "file could not be read, check with os.path.exists()" #check if file exists
    
    img = cv.medianBlur(img,5)
    cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
    circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
                                param1=30,param2=15,minRadius=0,maxRadius=0)
    circles = np.uint16(np.around(circles))
    for i in circles[0,:]:
        # draw the outer circle
        cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
        # draw the center of the circle
        cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
    cv.imshow('detected circles',cimg)
    cv.imwrite('detected_circle.jpg',cimg)
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    Result:

    enter image description here

    ADDITION

    Your other images need changes to detect the circles. You are currently not getting any circles, thus the error.

    Change param2=15 to param2=7 and you can detect the smallest image.

    I get:

    enter image description here

    For the larger image, change param2=15 to param2=13 and I get

    enter image description here