Python/Opencv 中不同颜色球的高尔夫球跟踪

fre*_*124 2 python opencv

只是寻找一些关于如何解决不同颜色球的高尔夫球跟踪问题的建议。

我探索过使用absdiff()来获取帧之间的差异来跟踪球,但它也可以获取球员和球杆的运动。另外,使用 HSV 来拾取特定颜色的球,但我希望能够拾取大多数颜色(白色、黄色、橙色、蓝色)。谢谢。

Ahm*_*vli 8

    1. 对每一帧进行预处理

    • 申请GaussianBlur

      gaussian_blurr = cv2.GaussianBlur(frame, (22, 22), 0)
      
      Run Code Online (Sandbox Code Playgroud)

      您可以更改参数,以上参数只是示例。

      假设下面是您的原始框架:

      在此输入图像描述

      高斯模糊将是:

      在此输入图像描述

      我们申请GaussianBlur减少噪音和异常值。

    • 将框架转换为 HSV 比例。

      hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
      
      Run Code Online (Sandbox Code Playgroud)

      在此输入图像描述

      转换hsv使我们能够检测当前帧中的球。

    • 申请inRange方法:

      greenLower = (29, 86, 6)
      greenUpper = (64, 255, 255)
      
      mask = cv2.inRange(hsv, greenLower, greenUpper)
      
      Run Code Online (Sandbox Code Playgroud)

      在此输入图像描述

      通过定义上下边界,我们通过声明 29 < 色调值 < 64、86 < 饱和度 < 255、6 < 值 < 255 来将球定位在框架中。

    • 申请erodedilate

      mask = cv2.erode(mask, None, iterations=2)
      mask = cv2.dilate(mask, None, iterations=2)
      
      Run Code Online (Sandbox Code Playgroud)

      在此输入图像描述

    erode常用dilate于图像预处理。

    erode删除对象边界上的像素。

    dilate连接由空格分隔的区域。来源

    1. 找到球的中心

  • 寻找轮廓

    cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    Run Code Online (Sandbox Code Playgroud)

    轮廓用于形状检测和识别。输出将是球位置的数组。我们需要掩模中最大的轮廓来找到中心。

    c = max(cnts, key=cv2.contourArea)
    ((x, y), radius) = cv2.minEnclosingCircle(c)
    M = cv2.moments(c)
    center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
    
    Run Code Online (Sandbox Code Playgroud)

    minClosingCircle将以最小面积覆盖物体。

    moments将返回加权面积。来源

    更新:如果您想查看球的质心,请添加以下内容:


    cv2.circle(frame, center, 5, (0, 0, 255), -1)
    
    Run Code Online (Sandbox Code Playgroud)

    结果:

    在此输入图像描述

  • 现在,如果我们组合所有帧,最终结果将是:


  • 在此输入图像描述

  • 最终球的质心:


  • 在此输入图像描述

现在,对于不同类型的球,您需要声明上限和下限,正如我们声明的greenUppergreenLower。然后应用从 1 开始的步骤。

完整代码:

import cv2
import imutils
import time

greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

vs = cv2.VideoCapture("input.mp4")
time.sleep(2.0)

while True:
    _, frame = vs.read()

    if frame is None:
        break

    blurred = cv2.GaussianBlur(frame, (11, 11), 0)
    width, height = frame.shape[:2]
    hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, greenLower, greenUpper)
    mask = cv2.erode(mask, None, iterations=2)
    mask = cv2.dilate(mask, None, iterations=2)
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    center = None

    if len(cnts) > 0:
        c = max(cnts, key=cv2.contourArea)
        ((x, y), radius) = cv2.minEnclosingCircle(c)
        M = cv2.moments(c)
        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))

        # To see the centroid clearly
        if radius > 10:
            cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 5)
            cv2.imwrite("circled_frame.png", cv2.resize(frame, (int(height / 2), int(width / 2))))
            cv2.circle(frame, center, 5, (0, 0, 255), -1)

    cv2.imshow("Frame", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

vs.release()
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)