如何检测真实图像上的椭圆

How to detect Ellipses on a real image

提问人:Davide 提问时间:9/29/2023 最后编辑:Davide 更新时间:10/11/2023 访问量:83

问:

我试着辨认出足球场的中场椭圆。我尝试了在线找到的不同解决方案,例如 Hough Transform 和 Template matching,但不幸的是我无法使它们正常工作。 图像是从真实的足球比赛中拍摄的,因此有不同的相机镜头和方向。

目前,我获得了最好的结果,过滤掉了音高之外的像素(使用颜色蒙版),并使用了一些变换,如高斯模糊、Canny,以及边缘轮廓和openCV中的fitEllipse()等技术。

蒙版后的起始图像:enter image description here

精明的形象:enter image description here

在这里,我执行了边缘轮廓,并使用aspect_ratio过滤掉了不相关的边缘:

contours, _ = cv2.findContours(canny_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

min_aspect_ratio = 3  # Minimum aspect ratio threshold (adjust as needed)
max_aspect_ratio = 50  # Maximum aspect ratio threshold (adjust as needed)

# Create a copy of the original image to draw bounding rectangles
image_with_rectangles = image.copy()

# Iterate through the contours
for contour in contours:
    # Calculate the aspect ratio of the bounding rectangle
    x, y, w, h = cv2.boundingRect(contour)
    aspect_ratio = float(w) / h

    # Check if the aspect ratio falls within the specified range
    if min_aspect_ratio < aspect_ratio < max_aspect_ratio:
        # Draw a green bounding rectangle around the contour
        cv2.rectangle(image_with_rectangles, (x, y), (x + w, y + h), (255, 255, 0), 2)

# Display the image with the bounding rectangles
print("Image with Bounding Rectangles")
cv2_imshow(image_with_rectangles)

filtered_contours = [
    cnt for cnt in contours
    if min_aspect_ratio < (float(cv2.boundingRect(cnt)[2]) / cv2.boundingRect(cnt)[3]) < max_aspect_ratio
]

result_image = np.zeros_like(original_image)  # Create a blank canvas

cv2.drawContours(result_image, filtered_contours, -1, (0, 255, 0), 2)  # Draw the filtered contours in green

# Display or save the result_image as needed
cv2_imshow(result_image)

带有边界矩形的图像:enter image description here

带有轮廓的图像:enter image description here

最后一步包括尝试拟合椭圆,我遇到了很多问题来使cv2.fitEllipse()工作,这是我的解决方案:

gray_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2GRAY)
cv2_imshow(gray_image)

# find the contours
contours,hierarchy = cv2.findContours(gray_image, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print("\nNumber of contours detected:", len(contours))

ellipse_image = original_image.copy()
ellipses = []
orientations = []

for c in filtered_contours:

  #if it contains at least 5 points (higher the value lower the number of ellipses)
  if len(c) >= 10:
    print(len(c))

    ellipse = cv2.fitEllipse(c)

    # Get the major and minor axes of the ellipse
    major_axis, minor_axis = ellipse[1]
    # Calculate the aspect ratio of the ellipse
    aspect_ratio = major_axis / minor_axis
    #we want a high aspect ratio, meaning that is much wider then taller
    if 0.1 <= aspect_ratio <= 0.2:
      print("\nRatio: ", aspect_ratio)
      print("M and m axes: ", major_axis, minor_axis)

      if major_axis < minor_axis:
        ellipses.append(ellipse)
        orientations.append(int(ellipse[2]))

for e in ellipses:
   cv2.ellipse(ellipse_image, e, (255, 255, 0), 2)


print("\nMiddlefield contour:")
cv2_imshow(ellipse_image)

最终结果:enter image description here

如何只保留一个椭圆(正确的椭圆)?

在 VITOR 的帖子后编辑

应用大量图像预处理操作来清理在输入图像上检测到的更多轮廓非常重要。如果你能得到一个良好而干净的中场椭圆形状,他的算法可以应用于检测并只保留一个椭圆。 结果有一些误报,但对椭圆的面积、纵横比和长度应用一些范围限制,我得到了很好的结果。

下面是一些例子。如您所见,这取决于过滤后的轮廓。

功:Contours Ellipse detected

还不错的结果:Contours Ellipse

错误结果(未检测到椭圆):Contours Ellipse

OpenCV 机器学习 目标检测 检测 椭圆

评论

0赞 Christoph Rackwitz 9/29/2023
不要尝试检测省略号。XY 问题。
0赞 Davide 9/29/2023
@ChristophRackwitz可以添加详细信息吗?
0赞 Christoph Rackwitz 9/30/2023
你应该解释你需要这个做什么,目标是什么,你为什么需要那个区域......
0赞 Davide 10/2/2023
@ChristophRackwitz我想突出中场区域,因为我想识别这些区域(如果我是左边还是右边),并了解谁在进攻,例如,一些统计数据。我不需要一个完美的椭圆,但我需要一个接近的椭圆,以便向我的教授展示演示。
2赞 Christoph Rackwitz 10/3/2023
所以这不是关于椭圆,而是关于在摄像机视图和足球场模型之间找到关系。那不是劈头发。这使您可以以实际导致某个地方的方式理解问题。商业解决方案要复杂得多,还假设相机具有固定位置并且只有平移/倾斜/变焦。您可以在此处尝试特征匹配,而无需此类假设。将视图与字段模型进行匹配。它必须看起来相当逼真,才能使功能相似。

答:

1赞 Vitor Pereira Matias 9/30/2023 #1

我所做的是用形态运算符关闭椭圆。并选择最大的椭圆(面积最大)。

  • 导入库并在 GRAYSCALE 中读取图像
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv.imread('K8hNf.png',0)
  • 形态学操作
kernel_square = cv.getStructuringElement(cv.MORPH_ELLIPSE,(50,50))
img = cv.morphologyEx(img,cv.MORPH_CLOSE,kernel_square,iterations=1)
  • 找到 Countour,并将图像从灰色更改为 RGB,这样我们就可以用绿色绘制椭圆。
contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
img = cv.cvtColor(img,cv.COLOR_GRAY2RGB)
  • 以下算法查找最大面积椭圆。这很简单。您还可以利用 .cv2.contourArea
largest_ellipse = None
max_area = 0

for contour in contours:
    if len(contour) >= 5:
        ellipse = cv.fitEllipse(contour)
        area = ellipse[1][0] * ellipse[1][1] * np.pi # Calculate the area of the fitted ellipse
        if area > max_area:
            max_area = area
            largest_ellipse = ellipse


if largest_ellipse is not None:
    cv.ellipse(img, largest_ellipse, (0,255,0),2)
else:
    print('No ellipses found')


plt.imshow(img,cmap='gray')

results

通过删除图像顶部不需要的线条并删除玩家骨架,您可以改善椭圆的拟合度。

由于相机角度失真,配件可能永远不会完美。

评论

1赞 Davide 10/3/2023
它仅适用于椭圆清晰可见且未被其他线触及的帧(如垂直中场线,有时它仍然存在)。此外,我还需要一些东西来丢弃没有中场区域的帧,否则会检测到到处都是椭圆
1赞 Davide 10/11/2023
更新:正如我所说,要使用此方法,您需要应用大量图像预处理,以仅保留良好的椭圆形状轮廓。经过一些测试,使用更干净的图像,我可以说可以应用此算法,您可以获得良好的结果,但仍然非常重要,拥有干净的轮廓并调整一些几何参数,如面积、纵横比和椭圆的长度,否则您可能会得到很多误报。