圆形霍夫变换遗漏圆圈
Circular Hough Transform misses circles
我在 Stack Overflow 上阅读了很多关于 Circular Hough 变换的内容,但我似乎遗漏了一些东西。我编写了一个程序来检测 "Bull's Eye" 目标的圆圈。然而,即使在使用了参数之后,该算法还是相当糟糕——它忽略了大部分圆圈,有一次它找到了一个圆圈,但似乎 "wander off"。我什至尝试应用 "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检测圆,然后绘制靠近中心的圆(我发现其他圆是假圆)。
我试过使用参数,这是我得到的最好的。我觉得这是一个足够简单的问题,让我感到困惑。我很感激任何帮助。
我的输入图片:
我的输出图像:
正如我在评论中提到的,您需要 运行 对不同半径范围的 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()
这是我得到的:
我在 Stack Overflow 上阅读了很多关于 Circular Hough 变换的内容,但我似乎遗漏了一些东西。我编写了一个程序来检测 "Bull's Eye" 目标的圆圈。然而,即使在使用了参数之后,该算法还是相当糟糕——它忽略了大部分圆圈,有一次它找到了一个圆圈,但似乎 "wander off"。我什至尝试应用 "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检测圆,然后绘制靠近中心的圆(我发现其他圆是假圆)。
我试过使用参数,这是我得到的最好的。我觉得这是一个足够简单的问题,让我感到困惑。我很感激任何帮助。
我的输入图片:
我的输出图像:
正如我在评论中提到的,您需要 运行 对不同半径范围的 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()
这是我得到的: