用OpenCV检测银球和反光球
Detecting silver and reflecting balls with OpenCV
我正在尝试使用 OpenCV 检测反映环境的银球:
用黑球,我通过检测圆圈成功了:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0);
gray = cv2.medianBlur(gray,5)
gray = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,3.5)
kernel = np.ones((3,3),np.uint8)
gray = cv2.erode(gray,kernel,iterations = 1)
gray = cv2.dilate(gray,kernel,iterations = 1)
circles = cv2.HoughCircles(gray, cv.CV_HOUGH_GRADIENT, 1, 260, \
param1=30, param2=65, minRadius=0, maxRadius=0)
但是使用银球程序时,我们没有得到任何结果。
看程序计算出的边缘,球的边缘很锋利。但是代码不识别任何球。
如何提高银球的检出率?我想到了两种方法:
- 改进边缘计算
- 使圆检测接受边缘不清晰的图像
那可能吗?最好的方法是什么?
非常感谢您的帮助。
你必须调整你的参数。 HoughCircles 函数在检测圆(即使有间隙)方面做得很好。请注意,HoughCircles 使用精明的边缘检测执行内部二值化。因此,您不必进行阈值处理。
根据你上面的图片,代码
import cv2
from matplotlib import pyplot as plt
import numpy as np
PATH = 'path/to/the/image.jpg'
img = cv2.imread(PATH, cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap='gray')
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=130, param2=30, minRadius=0, maxRadius=0)
if circles is not None:
for x, y, r in circles[0]:
c = plt.Circle((x, y), r, fill=False, lw=3, ec='C1')
plt.gca().add_patch(c)
plt.gcf().set_size_inches((12, 8))
plt.show()
产生结果
不同参数的含义是什么?
函数签名定义为
cv.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])
image 和 circles 是不言自明的,将被跳过。
方法
指定内部使用的 hough 算法的变体。如 documentation, only HOUGH_GRADIENT
is support atm. This method utilizes the 21HT (p.2, THE 2-1 HOUGH TRANSFORM) 算法中所述。这种变体的主要优点在于减少内存使用。使用 hough 变换检测圆的标准方法需要在 3D hough space(x、y 和半径)中进行搜索。然而,使用 21HT,你的 hough space 被减少到只有 2 个维度,这减少了相当数量的内存消耗。
dp
dp 参数设置逆累加器分辨率。可以找到一个很好的解释 。请注意,此说明使用标准霍夫变换作为示例。但是对于21HT效果是一样的。 21HT 的蓄能器与标准 HT 的蓄能器略有不同。
最小距离
简单地指定圆心之间的最小距离。在上面的代码示例中,它被设置为 20,这意味着两个检测到的圆的中心必须 至少 彼此相距 20 像素。我不确定 opencv 如何过滤掉圆圈,但扫描源代码看起来匹配度较低的圆圈被丢弃了。
参数 1
指定传递给 Canny Edge 算法的阈值。基本上它被称为 cv2.Canny(image, param1 / 2, param1)
.
参数2
这一段可能应该由更熟悉 opencv 源代码的人验证。
param2 指定累加器阈值。该值决定了圆 完成 的程度才能算作有效圆。我不确定给出参数的单位是什么。但是(再次扫描源代码)看起来是一个绝对的投票门槛(意思是直接受不同半径的影响)。
下图显示了不同的圆圈(或可以识别为圆圈的东西)。越往右,阈值必须越低才能检测到该圆圈。
最小半径和最大半径
只是将圆搜索限制在[minRadius, maxRadius]范围内的半径。如果您可以估计(或知道)要搜索的圆圈的大小,这将很有用(并且可以提高性能)。
我正在尝试使用 OpenCV 检测反映环境的银球:
用黑球,我通过检测圆圈成功了:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0);
gray = cv2.medianBlur(gray,5)
gray = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,3.5)
kernel = np.ones((3,3),np.uint8)
gray = cv2.erode(gray,kernel,iterations = 1)
gray = cv2.dilate(gray,kernel,iterations = 1)
circles = cv2.HoughCircles(gray, cv.CV_HOUGH_GRADIENT, 1, 260, \
param1=30, param2=65, minRadius=0, maxRadius=0)
但是使用银球程序时,我们没有得到任何结果。
看程序计算出的边缘,球的边缘很锋利。但是代码不识别任何球。
如何提高银球的检出率?我想到了两种方法: - 改进边缘计算 - 使圆检测接受边缘不清晰的图像 那可能吗?最好的方法是什么?
非常感谢您的帮助。
你必须调整你的参数。 HoughCircles 函数在检测圆(即使有间隙)方面做得很好。请注意,HoughCircles 使用精明的边缘检测执行内部二值化。因此,您不必进行阈值处理。
根据你上面的图片,代码
import cv2
from matplotlib import pyplot as plt
import numpy as np
PATH = 'path/to/the/image.jpg'
img = cv2.imread(PATH, cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap='gray')
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=130, param2=30, minRadius=0, maxRadius=0)
if circles is not None:
for x, y, r in circles[0]:
c = plt.Circle((x, y), r, fill=False, lw=3, ec='C1')
plt.gca().add_patch(c)
plt.gcf().set_size_inches((12, 8))
plt.show()
产生结果
不同参数的含义是什么?
函数签名定义为
cv.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])
image 和 circles 是不言自明的,将被跳过。
方法
指定内部使用的 hough 算法的变体。如 documentation, only HOUGH_GRADIENT
is support atm. This method utilizes the 21HT (p.2, THE 2-1 HOUGH TRANSFORM) 算法中所述。这种变体的主要优点在于减少内存使用。使用 hough 变换检测圆的标准方法需要在 3D hough space(x、y 和半径)中进行搜索。然而,使用 21HT,你的 hough space 被减少到只有 2 个维度,这减少了相当数量的内存消耗。
dp
dp 参数设置逆累加器分辨率。可以找到一个很好的解释
最小距离
简单地指定圆心之间的最小距离。在上面的代码示例中,它被设置为 20,这意味着两个检测到的圆的中心必须 至少 彼此相距 20 像素。我不确定 opencv 如何过滤掉圆圈,但扫描源代码看起来匹配度较低的圆圈被丢弃了。
参数 1
指定传递给 Canny Edge 算法的阈值。基本上它被称为 cv2.Canny(image, param1 / 2, param1)
.
参数2
这一段可能应该由更熟悉 opencv 源代码的人验证。 param2 指定累加器阈值。该值决定了圆 完成 的程度才能算作有效圆。我不确定给出参数的单位是什么。但是(再次扫描源代码)看起来是一个绝对的投票门槛(意思是直接受不同半径的影响)。 下图显示了不同的圆圈(或可以识别为圆圈的东西)。越往右,阈值必须越低才能检测到该圆圈。
最小半径和最大半径
只是将圆搜索限制在[minRadius, maxRadius]范围内的半径。如果您可以估计(或知道)要搜索的圆圈的大小,这将很有用(并且可以提高性能)。