Article directory
1. Introduction to Hough Transform
The classic Hough transform is used to recognize lines in images, but later the Hough transform was extended to recognize locations of arbitrary shapes, most commonly circles or ellipses.
"In many cases, an edge detector can be used as a preprocessing stage to obtain image points or image pixels on a desired curve in image space. However, due to imperfections in the image data or in the edge detector, the desired curve may exist Missing points or pixels, and spatial deviations between ideal lines/circles/ellipses and noisy edge points are obtained from edge detectors. For these reasons, grouping the extracted edge features into an appropriate set of lines, circles or ellipses is usually Very important. The purpose of the Hough Transform is to solve this problem by performing an explicit voting process on a parameterized set of image objects, so that edge points can be grouped as object candidates." - Wiki-Hough Transform .
2. Hough transform parameterization
A circle can be fully defined with three parameters: center coordinates (A, b) and radius (R):
x = a + Rcosθ
y = b + Rsinθ
As theta varies from 0 to 360, a full circle of radius R is created.
So, using the Circle Hough transform, we want to find triplets of (x, y, R) from the image. In other words, our purpose is to find these three parameters.
Therefore, we need to construct a 3D accumulator for the Hough transform, which will be very inefficient. Therefore, OpenCV uses a more sophisticated method, the Hough Gradient method using edge gradient information.
3. Hough transform source code
The function we are using here is cv2.HoughCircles(). It has a lot of arguments, which are well explained in the docs. So we go straight to the code:
import cv2
import numpy as np
from matplotlib import pyplot as plt
bgr_img = cv2.imread('hg.jpg') # read as it is
if bgr_img.shape[-1] == 3: # color image
b,g,r = cv2.split(bgr_img) # get b,g,r
rgb_img = cv2.merge([r,g,b]) # switch it to rgb
gray_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2GRAY)
else:
gray_img = bgr_img
img = cv2.medianBlur(gray_img, 5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
plt.subplot(121),plt.imshow(rgb_img)
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(cimg)
plt.title('Hough Transform'), plt.xticks([]), plt.yticks([])
plt.show()
4. Case analysis:
4.1 False circles
So far, it's been working fine:
4.2 A circle should not be considered as a hidden circle in the following cases
4.3 Make the effect better by blurring more content
img = cv2.medianBlur(gray_img, 25);
4.4 Preprocessing is crucial
In general, algorithms tend to extract too many circular features without blurring. So, to be more successful, preprocessing seems to be crucial:
4.5 Set a more appropriate fuzzy value
Use fuzzy value 51:
img = cv2.medianBlur(gray_img, 51);