圆形霍夫变换错过了圆圈
Posted
技术标签:
【中文标题】圆形霍夫变换错过了圆圈【英文标题】:Circular Hough Transform misses circles 【发布时间】:2015-11-24 01:24:31 【问题描述】:我在 Stack Overflow 上阅读了很多关于 Circular Hough 变换的信息,但我似乎遗漏了一些东西。我编写了一个程序来检测“靶心”目标的圆圈。然而,即使在使用参数之后,该算法也相当糟糕——它忽略了大部分圆圈,有一次它找到了一个圆圈,但似乎“走开了”。我什至尝试过使用“Unsharp Mask”但无济于事。我已经添加了我的代码、我开始使用的图像和输出。我希望有人能指出我正确的方向。
import cv2
import cv2.cv as cv
import numpy as np
import math
# Load Image
img = cv2.imread('circles1.png',0)
# Apply Unsharp Mask
tmp = cv2.medianBlur(img,5)
img = cv2.addWeighted(img,1.5,tmp,-0.5,0)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
# Hough Transform
circles = cv2.HoughCircles(img,cv.CV_HOUGH_GRADIENT,1,5,
param1=100,param2=100,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
# Go over circles, eliminating the ones that are not cocentric enough
height, width = img.shape
center = (width/2,height/2)
for i in circles[0,:]:
# draw the outer circle
if math.sqrt((center[0]-i[0])**2 + (center[1]-i[1])**2) < 15:
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),1)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
快速解释:我加载图像,应用 Unsharp Mask,使用 Hough Transfrom 检测圆,然后绘制靠近中心的圆(我发现其他圆都是假圆)。
我尝试使用参数,这是我得到的最好的。我觉得这是一个足够简单的问题,让我感到困惑。我感谢任何帮助。
我的输入图片:
我的输出图片:
【问题讨论】:
answers.opencv.org/question/31246/… 您必须多次迭代cv2.HoughCircles
,更改 minRadius
和 maxRadius
参数,直到检测到所有圆圈。
【参考方案1】:
正如我在评论中提到的,您需要针对不同的半径范围运行cv2.HoughCircles
的连续迭代,以确保获得所有圆。使用圆形霍夫变换的工作方式,指定具有相当大范围的最小和最大半径将是不准确的并且也会很慢。他们没有在文档中告诉您这一点,但要使循环霍夫变换成功工作,以下两件事需要有效:
maxRadius < 3*minRadius
maxRadius - minRadius < 100
通过上述方式,一味地使最小半径非常小而最大半径非常大不会给您带来很好的效果。因此,您可以做的是从...开始...说...radius=1
,然后以 20 步为单位迭代到radius=300
。在每个 20 块之间,运行cv2.HoughCircles
并使用这些轮廓更新您的图像。
这样做只需要对您的代码进行很少的修改。顺便说一句,我删除了不锐化的遮罩,因为我使用它的效果很差。我还稍微更改了cv2.HoughCircles
中的几个参数,以便根据您的情况使其尽可能地发挥作用:
import cv2
import cv2.cv as cv
import numpy as np
import math
# Load Image
img = cv2.imread('circles1.png',0)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
# Specify different radii
radii = np.arange(0,310,10)
# For each pair of radii...
for idx in range(len(radii)-1):
# Get the minimum and maximum radius
# Note you need to add 1 to each minimum
# as the maximum of the previous pair covers this new minimum
minRadius = radii[idx]+1
maxRadius = radii[idx+1]
# Hough Transform - Change here
circles = cv2.HoughCircles(img,cv.CV_HOUGH_GRADIENT,1,5,
param1=25,param2=75,minRadius=minRadius,maxRadius=maxRadius)
# Skip if no circles are detected - Change here
if circles is None:
continue
circles = np.uint16(np.around(circles))
# Go over circles, eliminating the ones that are not cocentric enough
height, width = img.shape
center = (width/2,height/2)
for i in circles[0,:]:
# draw the outer circle
if math.sqrt((center[0]-i[0])**2 + (center[1]-i[1])**2) < 15:
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),1)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
我得到了这个数字:
不幸的是,它并不完美,因为它无法检测到所有圆圈。您必须尝试使用 cv2.HoughCircles
函数,直到获得好的结果。
但是,我不建议在此处使用 cv2.HoughCircles
。我可以建议改用cv2.findContours
吗?这会找到图像中的所有轮廓。在这种情况下,这些将是黑色圆圈。但是,您需要反转图像,因为cv2.findContours
假设非零像素是对象像素,因此我们可以假设np.uint8
类型从图像中减去 255:
# Make copy of original image
cimg2 = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# Find contours
contours,_ = cv2.findContours(255 - img, cv2.RETR_LIST, cv.CV_CHAIN_APPROX_NONE)
# Draw all detected contours on image in green with a thickness of 1 pixel
cv2.drawContours(cimg2, contours, -1, color=(0,255,0), thickness=1)
# Show the image
cv2.imshow('detected circles', cimg2)
cv2.waitKey(0)
cv2.destroyAllWindows()
这是我得到的:
【讨论】:
非常感谢。他们在文档中没有提到这一点真的很奇怪,但是是的,问题是霍夫不能处理同心圆。这为我解决了这个问题。 完全没问题。如果我帮助了您并且您没有更多问题,请考虑接受我的回答。这可以通过单击我的帖子顶部左侧的向上和向下箭头下方的复选标记图标来完成。非常感谢! 解释得很好(+1) @GeorgeProfenza - 谢谢 :) 感谢您的精彩回答。一个问题:您输入 JPG 图像而不是像 @Bloodworth 这样的 PNG 是否有任何特殊原因?以上是关于圆形霍夫变换错过了圆圈的主要内容,如果未能解决你的问题,请参考以下文章
Python+opencv 机器视觉 - 基于霍夫圈变换算法检测图像中的圆形实例演示