Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Python OpenCV 365 day learning plan, enter the graphics realm with eraser. This blog is the 35th in the series.

Foundation of basic knowledge

Through retrieval of relevant materials, WE learned a little bit of superficial knowledge about Hough circle detection. The basic content of hough circle detection is that any non-zero pixel point on an image may be a point on a potential circle. Through the voting calculation, the cumulative coordinate plane is generated, and then a cumulative weight is set to locate the circle.

In Cartesian coordinates, the equation of a circle is (x−a)2+(y−a)2= R2 (x−a) ^2 +(y−a) ^2= R ^2(x− A)2+(y−a)2= R2, where (a,b) is the center of the circle and r is the radius. You can draw a diagram to show this.

And according to the picture, we can see the following results

X =a+rcos⁡θx=a+r \cos \thetax=a+rcosθ y=b+rsin⁡θy=b+ r\sin \thetay=b+rsinθ A =x−rcos⁡θa= x-R \cos \thetaa=x− Rcos θb=y − Rsin ⁡θb= Y-R \sin \thetab=y−rsinθ

And then there are a couple of conclusions that are not very easy to understand, but kind of make sense.

All circles passing through a point in cartesian coordinates, mapped to abR coordinates are a three-dimensional curve or interpreted as a point in the Cartesian xy plane x0,y0x_0,y_0x0,y0, corresponding to ABR forming a three-dimensional space, is a surface of space, for a point in the ABR plane, It corresponds to the Cartesian xy plane which is a circle.

After all non-zero pixels in the cartesian coordinates of all round, constitutes the abr many three-dimensional curve coordinate system In cartesian coordinate system on the same circle equation is the same at all points, they are mapped to abr is the same point in the coordinate system, so that point after accumulated to a certain number (usually set greater than a threshold), can be considered to be round.

If the three points in the xy plane (x0, y0), (x1, y1), (x2, y2) (x_0, y_0), (x_1, y_1), (x_2, y_2) (x0, y0), (x1, y1), (x2, y2), In abR three dimensional space are the corresponding three space surfaces (at this time ABR equals constant). The above contents are described as the following equation: (x0 – a) 2 + (y0 – a) 2 = r2 (x_0 – a) ^ 2 + (y_0 – a) ^ 2 = r ^ 2 (x0 – a) 2 + (y0 – a) 2 + 2 = r2 (x1 – a) (y1 – a) 2 = r2 (x_1 – a) ^ 2 + (y_1 – A) ^ 2 = r ^ 2 (x1 – a) 2 + (y1 – a) 2 = r2 (x2 – a) 2 + 2 = (y2 – a) r2 (x_2 – a) ^ 2 + (y_2 – a) ^ 2 = r ^ 2 (x2 – a) 2 + 2 = r2 (y2 – a)

By solving these three equations, we can get abR. This shows (x0, y0), (x1, y1), (x2, y2) (x_0, y_0), (x_1, y_1), (x_2, y_2) (x0, y0), (x1, y1), The three points (x2,y2) lie on the circle determined by abR (that is, ABR represents the coordinates of the center of the circle (x,y) and the radius of the circle r).

The above description is the principle of the standard Hough circle transformation, but the calculation of three-dimensional space is very large, the standard Hough circle change is difficult to be applied in practice. Hence the function covered in this article, hough gradient method, also known as 2-1 hough transform (21HT).

The function prototype

Python OpenCV provides the HoughCircles function to find circles.

circles = cv2.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])
Copy the code

The parameters are as follows:

  • image: Input image;
  • method: Method of detecting circles, currently supportedcv2.HOUGH_GRADIENT;
  • dp: The accumulator resolution is inversely proportional to the image resolution,dpThe larger the fetch, the smaller the accumulator array, generally 1 by default;
  • minDist: Distance between the center of a circle;
  • param1: edge detection gradient value, Canny function high threshold value, default 100;
  • param2:cv2.HOUGH_GRADIENTAccumulator threshold. The smaller the threshold, the more circles are detected. The default value is 100.
  • minRadius: Minimum radius, in pixels;
  • maxRadius: Maximum radius, in pixels;

The parameters of each vector in the return value are: the first element is the abscissa of the circle, the second is the ordinate, and the third is the radius.

Note: minRadius and maxRadius can be selected as circles. If not, keep the default value 0.

Test code as follows, run can directly view the effect.

import cv2


src = cv2.imread("./core.jpg")

# Image preprocessing
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray, 7)

circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1.60, param1=190, param2=30, minRadius=50, maxRadius=0)

# TypeError: Argument 'radius' is required to be an integer
for x, y, r in circles[0]:
    cv2.circle(src, (int(x), int(y)), int(r), (0.0.255), 2, cv2.LINE_AA)
cv2.imshow('circle', src)
cv2.waitKey(0)

cv2.destroyWindow()
Copy the code

The operation effect is shown in the figure below. Although there is no problem in the detection, it does cost a lot of time in the process of parameter tuning, mainly in theminDistThe parameters,param1If the parameters are not adjusted properly, the following situation will occur.

Hough circle detection is sensitive to noise, so median filtering should be carried out before hough circle detection. Gaussian filter is used for denoising, and the modified code is as follows:

gaussian = cv2.GaussianBlur(gray, (7.7),0)

circles = cv2.HoughCircles(gaussian, cv2.HOUGH_GRADIENT, 1.60, param1=220, param2=30, minRadius=50, maxRadius=0)
Copy the code

If you also want to add edge detection, code tuning becomes more tedious, such as adding Canny operators

gaussian = cv2.GaussianBlur(gray, (7.7),0)
# Use Canny for edge detection
edges = cv2.Canny(gaussian,160.180, apertureSize=3)
cv2.imshow("edges",edges)
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1.60, param1=1500, param2=30, minRadius=50, maxRadius=0)
Copy the code

The final result is also satisfactory

If the following error occurs during the running of the code, it indicates that no circle is found and you can continue to modify parameters.

TypeError: 'NoneType' object is not subscriptable
Copy the code