I'm trying to locate the circles in this image using the Hough transform, however I can't get good results, in fact they are quite bad, however I don't understand what's wrong, the image looks quite clean to me
here is the code:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(drilling_gray_image, cv2.MORPH_CLOSE, kernel, iterations=2)
cv2_imshow(morph)
plt.figure(figsize=(20, 4))
plt.imshow(morph, cmap='gray', vmin=0, vmax=255)
_, bin_image = cv2.threshold(morph, 128, 255, cv2.THRESH_BINARY)
plt.figure(figsize=(20, 4))
plt.imshow(bin_image, cmap='gray', vmin=0, vmax=255)
rows = bin_image.shape[0]
circles = cv2.HoughCircles(bin_image, cv2.HOUGH_GRADIENT, minDist=10, dp=rows / 16, param1=100, param2=200, minRadius=0, maxRadius=0)
print(circles)
result = drilling_gray_image.copy()
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
center = (i[0], i[1])
# circle center
cv2.circle(result, center, 1, (0, 100, 100), 3)
# circle outline
radius = i[2]
cv2.circle(result, center, radius, (255, 0, 255), 3)
plt.figure(figsize=(20, 4))
plt.imshow(result, cmap='gray', vmin=0, vmax=255)
here you can find the starting image: link
I try to follow this example that is similar to my case: stackoverflow
can anybody help me in detecting the circle in the image after the binarization?
i am not the expert on HoughCircle Algorithm but let me show you how i would do it:
Also about the parameters of the HoughCircle Algorithm:
minDist
: minimum distance between any to circle centers.dp
: just use recommended value 1.5 except for very smal circles.param1
: high threshold for Canny Edge Detection, also low threshold is set to half of param1
. Therefore first try canny on your image and find the best value for this.param2
: i am not exactly sure about this one but smaller means more circles. In the documentation it is explained as it is the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.minRadius
: name is the explanationmaxRadius
: name is the explanationFor tuning the HoughCircles transform, first give fixed values to minDist
, minRadius
and maxRadius
according to your circle's radius. Choose the best canny high threshold value by applying cv2.Canny()
and set it to param1
and use the recomended dp = 1.5
. Finally, play with the last remaining variable which is param2
.
Now, for your example i divided the circles into 3 categories according to their radius, 2 big ones on the left (green colored), 3 mid sized ones at the bottom (blue colored), and the remaining small ones (red colored). After running the algorithm for each category this is the final result:
As you see for the mid sized circles there is a false one inside a green circle. You can eliminate theese type false cirles with various methods for example after finding each circle draw them filled on the source image. I hope this is helpful for you.
This is the final code:
import cv2
import numpy
#Read the image and get blurred version
img = cv2.imread('image.png')
result = img.copy()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray,9)
#Run the hough algorithm three times
small_circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, minDist=20, dp=1, param1=100, param2=30, minRadius=7, maxRadius=40)
big_circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, minDist=100, dp=1, param1=100, param2=20, minRadius=90, maxRadius=120)
mid_circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, minDist=60, dp=1, param1=100, param2=12, minRadius=50, maxRadius=65)
#Draw detected small circles
if small_circles is not None:
small_circles = numpy.uint16(numpy.around(small_circles))
for i in small_circles[0, :]:
center = (i[0], i[1])
radius = i[2]
cv2.circle(result, center, radius, (0, 0, 255), 3)
#Draw detected big circles
if big_circles is not None:
big_circles = numpy.uint16(numpy.around(big_circles))
for i in big_circles[0, :]:
center = (i[0], i[1])
radius = i[2]
cv2.circle(result, center, radius, (0, 255, 0), 3)
#Draw detected mid circles
if mid_circles is not None:
mid_circles = numpy.uint16(numpy.around(mid_circles))
for i in mid_circles[0, :]:
center = (i[0], i[1])
radius = i[2]
cv2.circle(result, center, radius, (255, 0, 0), 3)
#Show the result image
cv2.imshow('img',cv2.resize(result,(0,0),fx=0.5,fy=0.5))
cv2.waitKey()