使用 opencv 和 python 的 HoughCircles 圆检测-
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26254287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HoughCircles circle detection using opencv and python-
提问by Shin
I am trying to use OpenCV's (Hough)Circle detection to.. detect circles. I created a solid circle on a black background, tried to play with the parameters, used blur and everything, but I am just not able to make it find anything.
我正在尝试使用 OpenCV 的 (Hough)Circle 检测来检测圆圈。我在黑色背景上创建了一个实心圆圈,尝试使用参数,使用模糊和所有内容,但我无法让它找到任何东西。
Any ideas, suggestions etc. would be great, thank you!
任何想法,建议等都会很棒,谢谢!
my current code is something like this:
我目前的代码是这样的:
import cv2
import numpy as np
"""
params = dict(dp=1,
minDist=1,
circles=None,
param1=300,
param2=290,
minRadius=1,
maxRadius=100)
"""
img = np.ones((200,250,3), dtype=np.uint8)
for i in range(50, 80, 1):
for j in range(40, 70, 1):
img[i][j]*=200
cv2.circle(img, (120,120), 20, (100,200,80), -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
canny = cv2.Canny(gray, 200, 300)
cv2.imshow('shjkgdh', canny)
gray = cv2.medianBlur(gray, 5)
circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 1, 20,
param1=100,
param2=30,
minRadius=0,
maxRadius=0)
print circles
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2)
cv2.circle(img,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('circles', img)
k = cv2.waitKey(0)
if k == 27:
cv2.destroyAllWindows()
采纳答案by Eliezer Bernart
Your code is working just fine. The problem is in your HoughCirclesthreshold parameters.
您的代码运行良好。问题在于您的HoughCircles阈值参数。
Let's try to understand the parameters that you're using from OpenCV Docs:
让我们尝试从OpenCV Docs了解您使用的参数:
param1 – First method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the higher threshold of the two passed to the Canny() edge detector (the lower one is twice smaller).
param2 – Second method-specific parameter. In case of CV_HOUGH_GRADIENT , 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.
param1 – 第一个特定于方法的参数。在 CV_HOUGH_GRADIENT 的情况下,它是传递给 Canny() 边缘检测器的两个阈值中较高的阈值(较低的阈值小两倍)。
param2 – 第二个特定于方法的参数。在 CV_HOUGH_GRADIENT 的情况下,它是检测阶段圆心的累加器阈值。它越小,检测到的假圆就越多。与较大累加器值相对应的圆圈将首先返回。
So, as you can see, internally the HoughCircles function calls the Canny edge detector, this means that you can use a gray image in the function, instead of their contours.
因此,如您所见,HoughCircles 函数在内部调用 Canny 边缘检测器,这意味着您可以在函数中使用灰度图像,而不是它们的轮廓。
Now reduce the param1to 30 and param2to 15 and see the results in the code that follows:
现在将 减少param1到 30 和param215,并在下面的代码中查看结果:
import cv2
import numpy as np
img = np.ones((200,250,3), dtype=np.uint8)
for i in range(50, 80, 1):
for j in range(40, 70, 1):
img[i][j]*=200
cv2.circle(img, (120,120), 20, (100,200,80), -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 1, 20,
param1=30,
param2=15,
minRadius=0,
maxRadius=0)
print circles
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2)
cv2.circle(img,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('circles', img)
k = cv2.waitKey(0)
if k == 27:
cv2.destroyAllWindows()


回答by Eric Leschinski
If you're not getting HoughCircles to bring you pixel perfect solutions for obvious circles then you're not using it right
如果您没有让 HoughCircles 为您提供针对明显圆圈的像素完美解决方案,那么您就没有正确使用它
Your mistake is you're trying to hand-tune your hyperparameters by yourself. That's not going to work. Have the computer auto-tune the parameters for you:
你的错误是你试图自己手动调整你的超参数。那是行不通的。让计算机为您自动调整参数:
import numpy as np
import argparse
import cv2
import signal
from functools import wraps
import errno
import os
import copy
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
orig_image = np.copy(image)
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
cv2.waitKey(0)
circles = None
minimum_circle_size = 100 #this is the range of possible circle in pixels you want to find
maximum_circle_size = 150 #maximum possible circle size you're willing to find in pixels
guess_dp = 1.0
number_of_circles_expected = 1 #we expect to find just one circle
breakout = False
max_guess_accumulator_array_threshold = 100 #minimum of 1, no maximum, (max 300?) the quantity of votes
#needed to qualify for a circle to be found.
circleLog = []
guess_accumulator_array_threshold = max_guess_accumulator_array_threshold
while guess_accumulator_array_threshold > 1 and breakout == False:
#start out with smallest resolution possible, to find the most precise circle, then creep bigger if none found
guess_dp = 1.0
print("resetting guess_dp:" + str(guess_dp))
while guess_dp < 9 and breakout == False:
guess_radius = maximum_circle_size
print("setting guess_radius: " + str(guess_radius))
print(circles is None)
while True:
#HoughCircles algorithm isn't strong enough to stand on its own if you don't
#know EXACTLY what radius the circle in the image is, (accurate to within 3 pixels)
#If you don't know radius, you need lots of guess and check and lots of post-processing
#verification. Luckily HoughCircles is pretty quick so we can brute force.
print("guessing radius: " + str(guess_radius) +
" and dp: " + str(guess_dp) + " vote threshold: " +
str(guess_accumulator_array_threshold))
circles = cv2.HoughCircles(gray,
cv2.cv.CV_HOUGH_GRADIENT,
dp=guess_dp, #resolution of accumulator array.
minDist=100, #number of pixels center of circles should be from each other, hardcode
param1=50,
param2=guess_accumulator_array_threshold,
minRadius=(guess_radius-3), #HoughCircles will look for circles at minimum this size
maxRadius=(guess_radius+3) #HoughCircles will look for circles at maximum this size
)
if circles is not None:
if len(circles[0]) == number_of_circles_expected:
print("len of circles: " + str(len(circles)))
circleLog.append(copy.copy(circles))
print("k1")
break
circles = None
guess_radius -= 5
if guess_radius < 40:
break;
guess_dp += 1.5
guess_accumulator_array_threshold -= 2
#Return the circleLog with the highest accumulator threshold
# ensure at least some circles were found
for cir in circleLog:
# convert the (x, y) coordinates and radius of the circles to integers
output = np.copy(orig_image)
if (len(cir) > 1):
print("FAIL before")
exit()
print(cir[0, :])
cir = np.round(cir[0, :]).astype("int")
for (x, y, r) in cir:
cv2.circle(output, (x, y), r, (0, 0, 255), 2)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
cv2.imshow("output", np.hstack([orig_image, output]))
cv2.waitKey(0)
To this:
对此:
For more information about what this is doing, see: https://stackoverflow.com/a/46500223/445131
有关此操作的更多信息,请参阅:https: //stackoverflow.com/a/46500223/445131

