A few days ago, I got an email from a PyImageSearch reader asking about circle detection. See below for the gist:
Hey Adrian,
Love your blog. I saw your post on detecting rectangles/squares in images, but I was wondering, how do you detect circles in images using OpenCV?
Thanks.
Great question.
As you’ve probably already found out, detecting circles in images using OpenCV is substantially harder than detecting other shapes with sharp edges.
But don’t worry!
In this blog post I’ll show you how to utilize the cv2.HoughCircles
function to detect circles in images using OpenCV.
To learn how to detect circles with OpenCV, just keep reading!
Looking for the source code to this post?
Jump Right To The Downloads SectionThe cv2.HoughCircles Function
In order to detect circles in images, you’ll need to make use of the cv2.HoughCircles
function. It’s definitely not the easiest function to use, but with a little explanation, I think you’ll get the hang of it.
Take a look at the function signature below:
cv2.HoughCircles(image, method, dp, minDist)
image
: 8-bit, single channel image. If working with a color image, convert to grayscale first.method
: Defines the method to detect circles in images. Currently, the only implemented method iscv2.HOUGH_GRADIENT
, which corresponds to the Yuen et al. paper.dp
: This parameter is the inverse ratio of the accumulator resolution to the image resolution (see Yuen et al. for more details). Essentially, the larger thedp
gets, the smaller the accumulator array gets.minDist
: Minimum distance between the center (x, y) coordinates of detected circles. If theminDist
is too small, multiple circles in the same neighborhood as the original may be (falsely) detected. If theminDist
is too large, then some circles may not be detected at all.param1
: Gradient value used to handle edge detection in the Yuen et al. method.param2
: Accumulator threshold value for thecv2.HOUGH_GRADIENT
method. The smaller the threshold is, the more circles will be detected (including false circles). The larger the threshold is, the more circles will potentially be returned.minRadius
: Minimum size of the radius (in pixels).maxRadius
: Maximum size of the radius (in pixels).
If this method seems complicated, don’t worry. It’s actually not too bad.
But I will say this — be ready to play around with the parameter values from image to image. The minDist
parameter is especially important to get right. Without an optimal minDist
value, you may end up missing out on some circles, or you may detecting many false circles.
Detecting Circles in Images using OpenCV and Hough Circles
Ready to apply the cv2.HoughCircles
function to detect circles in images?
Great. Let’s jump into some code:
# import the necessary packages import numpy as np import argparse import cv2 # construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required = True, help = "Path to the image") args = vars(ap.parse_args())
Lines 2-4 import the necessary packages we’ll need. We’ll utilize NumPy for numerical processing, argparse
for parsing command line arguments, and cv2
for our OpenCV bindings.
Then, on Lines 7-9 we parse our command line arguments. We’ll need only a single switch, --image
, which is the path to the image we want to detect circles in.
Let’s go ahead and load the image:
# load the image, clone it for output, and then convert it to grayscale image = cv2.imread(args["image"]) output = image.copy() gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
We load our image off disk on Line 12 and create a copy of it on Line 13 so we can draw our detected circles without destroying the original image.
As we’ll see, the cv2.HoughCircles
function requires an 8-bit, single channel image, so we’ll go ahead and convert from the RGB color space to grayscale on Line 14.
Okay, time to detect the circles:
# detect circles in the image circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100) # ensure at least some circles were found if circles is not None: # convert the (x, y) coordinates and radius of the circles to integers circles = np.round(circles[0, :]).astype("int") # loop over the (x, y) coordinates and radius of the circles for (x, y, r) in circles: # draw the circle in the output image, then draw a rectangle # corresponding to the center of the circle cv2.circle(output, (x, y), r, (0, 255, 0), 4) cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1) # show the output image cv2.imshow("output", np.hstack([image, output])) cv2.waitKey(0)
Detecting the circles is handled by the cv2.HoughCircles
function on Line 17. We pass in the image we want to detect circles as the first argument, the circle detection method as the second argument (currently, the cv2.cv.HOUGH_GRADIENT
method is the only circle detection method supported by OpenCV and will likely be the only method for some time), an accumulator value of 1.5 as the third argument, and finally a minDist
of 100 pixels.
A check is made on Line 20 to ensure at least one circle was found in the image.
Line 22 then handles converting our circles from floating point (x, y) coordinates to integers, allowing us to draw them on our output image.
From there, we start looping over the center (x, y) coordinates and the radius of the circle on Line 25.
We draw the actual detected circle on Line 28 using the cv2.circle
function, followed by drawing a rectangle at the center of the circle on Line 29.
Finally, Lines 32 and 33 display our output image.
So there you have it — detecting circles in images using OpenCV.
But let’s go ahead and take a look at some results.
Fire up a shell, and execute the following command:
$ python detect_circles.py --image images/simple.png
We’ll start with something simple, detecting a red circle on a black background:
Not bad! Our Python script has detected the red circle, outlined it in green, and then placed an orange square at the center of it.
Let’s move on to something else:
$ python detect_circles.py --image images/soda.png
Again, our Python script is able to detect the circular region of the can.
Now, let’s try the 8 circle problem.
In this problem we have one large circle, followed byĀ seven circles placed inside the large one.
Since this is a much smaller image than the previous ones (and we are detecting multiple circles), I’m going to adjust the minDist
to be 75 pixels rather than 100.
Hm. Now it looks like we have ran into a problem.
The cv2.HoughCircles
function was able to detect only seven of the circles instead of allĀ eight, leaving out the one in the center.
Why did this happen?
It’s due to the minDist
parameter. The centerĀ (x, y)Ā coordinates for the large outer circle are identical to the center inner circle, thus the center inner circle is discarded.
Unfortunately, there is not a way around this problem unless we make minDist
unreasonably small, and thus generating many “false” circle detections.
What's next? I recommend PyImageSearch University.
30+ total classes • 39h 44m video • Last updated: 12/2021
★★★★★ 4.84 (128 Ratings) • 3,000+ Students Enrolled
I strongly believe that if you had the right teacher you could master computer vision and deep learning.
Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?
Thatās not the case.
All you need to master computer vision and deep learning is for someone to explain things to you in simple, intuitive terms. And thatās exactly what I do. My mission is to change education and how complex Artificial Intelligence topics are taught.
If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here youāll learn how to successfully and confidently apply computer vision to your work, research, and projects. Join me in computer vision mastery.
Inside PyImageSearch University you'll find:
- ✓ 30+ courses on essential computer vision, deep learning, and OpenCV topics
- ✓ 30+ Certificates of Completion
- ✓ 39h 44m on-demand video
- ✓ Brand new courses released every month, ensuring you can keep up with state-of-the-art techniques
- ✓ Pre-configured Jupyter Notebooks in Google Colab
- ✓ Run all code examples in your web browser ā works on Windows, macOS, and Linux (no dev environment configuration required!)
- ✓ Access to centralized code repos for all 500+ tutorials on PyImageSearch
- ✓ Easy one-click downloads for code, datasets, pre-trained models, etc.
- ✓ Access on mobile, laptop, desktop, etc.
Summary
In this blog post I showed you how to use the cv2.HoughCircles
function in OpenCV to detect circles in images.
Unlike detecting squares or rectangles in images, detecting circles is substantially harder since we cannot reply on approximating the number of points in a contour.
To help us detect circles in images, OpenCV has supplied the cv2.HoughCircles
function.
While the cv2.HoughCircles
method may seem complicated at first, I would argue that the most important parameter to play with is the minDist
, or the minimum distance between the center (x, y) coordinates of detected circles.
If you set minDist
too small, you may end up with many falsely detected circles. On the other hand, if minDist
is too large, then you may end up missing some circles. Setting this parameter definitely takes some fine tuning.
Have a Question?
Do you have a question about OpenCV and Python? Just send me a message. And I’ll do my best to answer it on this blog.
Download the Source Code and FREE 17-page Resource Guide
Enter your email address below to get a .zip of the code and a FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning. Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!