如果使用 OpenCV 的 HoughCircles,是否有推荐的方法来确定 minRadius 以查找图像中的第一个圆?
Is there a recommended methodology to determine minRadius for finding the 1 circle in an image if using OpenCV's HoughCircles?
我需要找出最佳方法来选择用于 OpenCV cv2.HoughCircles function 的 minRadius 值。
我正在努力提高对美国稀有硬币进行分类的 Tensorflow CNN 的准确性。目前,CNN 正在审查 从 300x300 到 1024x1024
所有不同尺寸的 >10k 图像
为了提高模型的准确性,我试图在训练之前将硬币从图像中拉出来,并且只在硬币上而不是在其周围训练模型。
下面的代码在将硬币检测为圆形时工作正常,但我必须尝试几个 minRadius 值才能使 HoughCircles 函数正常工作。
在某些情况下,minRadius=270 适用于 600x600 和 785x1024,而在其他情况下,只有 r=200 适用于 600x600,但不适用于 785x1024。在其他情况下,只有 r=318 有效,但 317 或 319 无效。我没有找到一致的方法。
问题:是否有推荐的方法来确定 minRadius 以找到图像中的第一个圆?假设图像大小不同并且硬币占据图像的 50% 到 90%
以下是典型图像的示例:https://i.ebayimg.com/images/g/r5oAAOSwH8VeHNBf/s-l1600.jpg
https://i.ebayimg.com/images/g/~JsAAOSwGtdeyFfU/s-l1600.jpg
image = cv2.imread(r"C:\testimagesa.jpg")
output = image.copy()
height, width = image.shape[:2]
minRadius = 200
maxRadius =0
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(image=gray,
method=cv2.HOUGH_GRADIENT,
dp=1.2,
minDist=200*minRadius, #something large since we are looking for 1
param1=200,
param2=100,
minRadius=minRadius,
maxRadius=maxRadius
)
#Draw the circles detected
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circlesRound = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circlesRound:
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
plt.imshow(output)
else:
print ('No circles found')
这是一种不同的方法,可以将椭圆拟合到从阈值化图像中提取的最大轮廓。如果需要,您可以使用椭圆的长半径和短半径作为霍夫圆的近似值。
输入:
import cv2
import numpy as np
# read input
img = cv2.imread('s-l1600.jpg')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# apply morphology open and close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (21,21))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
# find largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# fit ellipse to contour and get ellipse center, minor and major diameters and angle in degree
ellipse = cv2.fitEllipse(big_contour)
(xc,yc),(d1,d2),angle = ellipse
print('center: ',xc,',',yc)
print('diameters: ',d1,',',d2)
# draw ellipse
result = img.copy()
cv2.ellipse(result, ellipse, (0, 0, 255), 2)
# draw circle at center
xc, yc = ellipse[0]
cv2.circle(result, (int(xc),int(yc)), 5, (0, 255, 0), -1)
cv2.imwrite("s-l1600_thresh.jpg", thresh)
cv2.imwrite("s-l1600_morph.jpg", morph)
cv2.imwrite("s-l1600_ellipse.jpg", result)
cv2.imshow("s-l1600_thresh", thresh)
cv2.imshow("s-l1600_morph", morph)
cv2.imshow("s-l1600_ellipse", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Otsu 阈值图像:
清理阈值图像:
根据显示椭圆轮廓和中心的输入轮廓拟合绘制的椭圆:
椭圆参数:
center: 504.1853332519531 , 524.3350219726562
diameters: 953.078125 , 990.545654296875
这是你的另一张图片。但在这里我使用 inRange().
使用颜色阈值
输入:
import cv2
import numpy as np
# read input
img = cv2.imread('s-l1600b.jpg')
# convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# get color bounds of red circle
lower =(0,0,0) # lower bound for each channel
upper = (150,150,150) # upper bound for each channel
# create the mask and use it to change the colors
thresh = cv2.inRange(hsv, lower, upper)
# apply morphology open and close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31,31))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
# find largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# fit ellipse to contour and get ellipse center, minor and major diameters and angle in degree
ellipse = cv2.fitEllipse(big_contour)
(xc,yc),(d1,d2),angle = ellipse
print('center: ',xc,',',yc)
print('diameters: ',d1,',',d2)
# draw ellipse
result = img.copy()
cv2.ellipse(result, ellipse, (0, 0, 255), 2)
# draw circle at center
xc, yc = ellipse[0]
cv2.circle(result, (int(xc),int(yc)), 5, (0, 255, 0), -1)
cv2.imwrite("s-l1600_thresh.jpg", thresh)
cv2.imwrite("s-l1600_morph.jpg", morph)
cv2.imwrite("s-l1600_ellipse.jpg", result)
cv2.imshow("s-l1600b_thresh", thresh)
cv2.imshow("s-l1600b_morph", morph)
cv2.imshow("s-l1600b_ellipse", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态学清理图像:
适合椭圆并绘制在输入上的最大外部轮廓:
椭圆参数:
center: 497.53564453125 , 639.7144165039062
diameters: 454.8548583984375 , 458.95843505859375
我需要找出最佳方法来选择用于 OpenCV cv2.HoughCircles function 的 minRadius 值。
我正在努力提高对美国稀有硬币进行分类的 Tensorflow CNN 的准确性。目前,CNN 正在审查 从 300x300 到 1024x1024
所有不同尺寸的 >10k 图像为了提高模型的准确性,我试图在训练之前将硬币从图像中拉出来,并且只在硬币上而不是在其周围训练模型。
下面的代码在将硬币检测为圆形时工作正常,但我必须尝试几个 minRadius 值才能使 HoughCircles 函数正常工作。
在某些情况下,minRadius=270 适用于 600x600 和 785x1024,而在其他情况下,只有 r=200 适用于 600x600,但不适用于 785x1024。在其他情况下,只有 r=318 有效,但 317 或 319 无效。我没有找到一致的方法。
问题:是否有推荐的方法来确定 minRadius 以找到图像中的第一个圆?假设图像大小不同并且硬币占据图像的 50% 到 90%
以下是典型图像的示例:https://i.ebayimg.com/images/g/r5oAAOSwH8VeHNBf/s-l1600.jpg https://i.ebayimg.com/images/g/~JsAAOSwGtdeyFfU/s-l1600.jpg
image = cv2.imread(r"C:\testimagesa.jpg")
output = image.copy()
height, width = image.shape[:2]
minRadius = 200
maxRadius =0
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(image=gray,
method=cv2.HOUGH_GRADIENT,
dp=1.2,
minDist=200*minRadius, #something large since we are looking for 1
param1=200,
param2=100,
minRadius=minRadius,
maxRadius=maxRadius
)
#Draw the circles detected
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circlesRound = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circlesRound:
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
plt.imshow(output)
else:
print ('No circles found')
这是一种不同的方法,可以将椭圆拟合到从阈值化图像中提取的最大轮廓。如果需要,您可以使用椭圆的长半径和短半径作为霍夫圆的近似值。
输入:
import cv2
import numpy as np
# read input
img = cv2.imread('s-l1600.jpg')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# apply morphology open and close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (21,21))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
# find largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# fit ellipse to contour and get ellipse center, minor and major diameters and angle in degree
ellipse = cv2.fitEllipse(big_contour)
(xc,yc),(d1,d2),angle = ellipse
print('center: ',xc,',',yc)
print('diameters: ',d1,',',d2)
# draw ellipse
result = img.copy()
cv2.ellipse(result, ellipse, (0, 0, 255), 2)
# draw circle at center
xc, yc = ellipse[0]
cv2.circle(result, (int(xc),int(yc)), 5, (0, 255, 0), -1)
cv2.imwrite("s-l1600_thresh.jpg", thresh)
cv2.imwrite("s-l1600_morph.jpg", morph)
cv2.imwrite("s-l1600_ellipse.jpg", result)
cv2.imshow("s-l1600_thresh", thresh)
cv2.imshow("s-l1600_morph", morph)
cv2.imshow("s-l1600_ellipse", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Otsu 阈值图像:
清理阈值图像:
根据显示椭圆轮廓和中心的输入轮廓拟合绘制的椭圆:
椭圆参数:
center: 504.1853332519531 , 524.3350219726562
diameters: 953.078125 , 990.545654296875
这是你的另一张图片。但在这里我使用 inRange().
使用颜色阈值输入:
import cv2
import numpy as np
# read input
img = cv2.imread('s-l1600b.jpg')
# convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# get color bounds of red circle
lower =(0,0,0) # lower bound for each channel
upper = (150,150,150) # upper bound for each channel
# create the mask and use it to change the colors
thresh = cv2.inRange(hsv, lower, upper)
# apply morphology open and close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31,31))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
# find largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# fit ellipse to contour and get ellipse center, minor and major diameters and angle in degree
ellipse = cv2.fitEllipse(big_contour)
(xc,yc),(d1,d2),angle = ellipse
print('center: ',xc,',',yc)
print('diameters: ',d1,',',d2)
# draw ellipse
result = img.copy()
cv2.ellipse(result, ellipse, (0, 0, 255), 2)
# draw circle at center
xc, yc = ellipse[0]
cv2.circle(result, (int(xc),int(yc)), 5, (0, 255, 0), -1)
cv2.imwrite("s-l1600_thresh.jpg", thresh)
cv2.imwrite("s-l1600_morph.jpg", morph)
cv2.imwrite("s-l1600_ellipse.jpg", result)
cv2.imshow("s-l1600b_thresh", thresh)
cv2.imshow("s-l1600b_morph", morph)
cv2.imshow("s-l1600b_ellipse", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态学清理图像:
适合椭圆并绘制在输入上的最大外部轮廓:
椭圆参数:
center: 497.53564453125 , 639.7144165039062
diameters: 454.8548583984375 , 458.95843505859375