首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >热搜第一!常州队进球无效?用YOLO建个足球追踪系统试试看!

热搜第一!常州队进球无效?用YOLO建个足球追踪系统试试看!

原创
作者头像
CoovallyAIHub
发布2025-07-09 10:02:41
发布2025-07-09 10:02:41
2760
举报

【导读】

7月6日晚,“苏超”联赛第六轮,常州客场对战淮安,最终0∶0握手言和。这场高温下的鏖战,是常州队在“苏超”中拿下的首个积分。

然而,“常州进球无效”却在赛后登上微博热搜第一,引发大量讨论——这个进球到底应不应该算? 这一次,我们从AI的角度切入,试着用YOLO目标检测技术搭建一个足球比赛追踪系统,看看AI是否能还原现场,为争议判罚提供“技术支持”。


一、为什么要用AI辅助足球判罚?

人眼观看有盲区,裁判也可能会错过某些细节。而现代AI视觉系统可以做到:

  • 识别并追踪每一个球员;
  • 实时定位足球在场上的运动轨迹;
  • 精准分析越位、进球等关键事件。

尤其是在“是否越过门线”、“是否越位”等边界判罚上,AI能发挥巨大作用。


二、传统流程:从零搭建一个YOLO足球追踪系统

数据采集与标注

  • 使用视频帧截取工具,将比赛视频转为图像序列(如每秒5帧);
  • 使用CVAT、LabelImg等工具对球员、足球、裁判等目标进行框选标注;
  • 导出为YOLO格式的标签文件。
代码语言:javascript
复制
/data
  └── images/
      └── match01_001.jpg
  └── labels/
      └── match01_001.txt  # YOLO格式标签

微调YOLO模型

  • 使用YOLOv8预训练模型进行迁移学习;
  • 自定义类如 ballplayerreferee
  • 设置好 match.yaml 后训练。
代码语言:javascript
复制
      yolo task=detect mode=train model=yolov8n.pt data=match.yaml epochs=50 imgsz=640
代码语言:javascript
复制
from ultralytics import YOLO

model = YOLO("../assets/weights/best.pt")

result = model.predict(source="../assets/source_videos/B1606b0e6_1 (28).mp4", 
                       save=True,
                       stream=True)
代码语言:javascript
复制
import cv2

# Retrieve and visualize the first result
first_result = next(result)  # Get the first result from the generator
annotated_frame = first_result.plot()  # Overlay detections on the frame
代码语言:javascript
复制
# Display the annotated frame
cv2.imshow("YOLO Detection", annotated_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

目标追踪机制详解

检测模型可以在每一帧中识别出球员和足球,但不会“记住”谁是谁。YOLO是静态检测器,追踪需要跨帧关联。

什么是目标追踪?

目标追踪是指在视频序列中,保持同一物体ID一致,并绘制其移动轨迹。我们需要结合:

  • 位置:距离与上帧目标位置的接近程度;
  • 外观:颜色特征、尺寸、长宽比等;
  • 运动轨迹:使用卡尔曼滤波器预测移动趋势。

首先,我们应该从视频文件中提取帧。

代码语言:javascript
复制
# funcs.py
import cv2
import numpy as np
from typing import List

def read_video_frames(video_path: str) -> List[np.ndarray]:
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        raise IOError(f"Cannot open video: {video_path}")

    frames = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        frames.append(frame)
    cap.release()
    return frames

批量推理并缓存,跟踪检测目标

代码语言:javascript
复制
import supervision as sv
from typing import Any, Dict

def run_tracking(detections: List[Any]) -> Dict[str, List[Dict[int, Dict[str, List[float]]]]]:
    tracker = sv.ByteTrack()
    results = {"players": [], "referees": [], "ball": []}

    for det in detections:
        cls_names = det.names
        name2id = {v: k for k, v in cls_names.items()}
        sv_det = sv.Detections.from_ultralytics(det)

        for i, cls_id in enumerate(sv_det.class_id):
            if cls_names[cls_id] == "goalkeeper":
                sv_det.class_id[i] = name2id["player"]

        tracked = tracker.update_with_detections(sv_det)

        frame_result = {"players": {}, "referees": {}, "ball": {}}
        for t in tracked:
            bbox, cls_id, track_id = t[0].tolist(), t[3], t[4]
            if cls_id == name2id["player"]:
                frame_result["players"][track_id] = {"bbox": bbox}
            elif cls_id == name2id["referee"]:
                frame_result["referees"][track_id] = {"bbox": bbox}

        for t in sv_det:
            if t[3] == name2id["ball"]:
                frame_result["ball"][1] = {"bbox": t[0].tolist()}

        for key in results:
            results[key].append(frame_result[key])
    return results

绘制可视化框和导出

动图封面
动图封面

✅ 颜色聚类辅助身份识别

比赛中球衣颜色不同,我们使用 K-Means 聚类对图像上半部分进行颜色分割:

代码语言:javascript
复制
# 图像预处理
upper_half = frame[0:int(h/2), :, :]  # 获取图像上半部分
pixels = upper_half.reshape(-1, 3)

# 聚类为两个颜色区域(假设为球衣+背景)
kmeans = KMeans(n_clusters=2).fit(pixels)

# 找出背景标签(角落像素最多的聚类中心)
corner_pixels = frame[0:10, 0:10, :].reshape(-1, 3)
corner_labels = kmeans.predict(corner_pixels)
background_label = np.bincount(corner_labels).argmax()

# 得到球员球衣颜色中心
player_cluster_color = kmeans.cluster_centers_[1 - background_label]
动图封面
动图封面

DeepSORT集成

使用DeepSORT,可以将检测结果与颜色特征结合,自动分配ID并持续追踪:

代码语言:javascript
复制
features = extract_color_features(frame, box)
tracker.update(box, features)

最终,我们可在视频中呈现出球员编号、实时轨迹线、速度变化等效果。

动态边框与行为分析

  • 在图像中渲染边框、轨迹线、球员速度;
  • 识别关键事件帧(如足球接近门线、球员碰撞)。

球员分割

可使用YOLACT、RTMDet等模型,对遮挡球员进行实例分割,辅助精确识别和ID保持。

球轨迹插值

处理掉帧、遮挡时足球的轨迹连续性,可使用插值方法:

代码语言:javascript
复制
# 示例:两帧之间线性插值
ball_pos_frame1 = (x1, y1)
ball_pos_frame2 = (x2, y2)
interpolated = [(x1 + i*(x2-x1)/n, y1 + i*(y2-y1)/n) for i in range(1, n)]
动图封面
动图封面

三、这些流程的“痛点”

  • 标注数据成本高,需逐帧框选目标;
  • 训练和追踪逻辑复杂,涉及多种算法拼接;
  • 调参、可视化、测试周期长;
  • 需要本地配置深度学习环境,对初学者不友好。

四、对比总结表格

模块

传统流程

Coovally平台

模型训练

YOLO下载 + 迁移学习 + 手动调参

一键启动,支持预训练YOLOv8

目标追踪

需接入DeepSORT、ReID模块

平台内置多种追踪算法

轨迹渲染

需OpenCV绘图脚本

自动轨迹线、速度变化可视化

球衣颜色辅助

K-Means聚类手动实现

调用SSH本地修改

部署环境

需显卡、PyTorch、依赖配置

无需安装,云端训练


总结

这场0∶0背后的故事,不止是比分。

“我们从来不是因为看到希望才坚持,而是因为坚持,才能看到希望。”

而技术的价值也在于此:让争议判罚有“辅助证据”,让地方联赛也能享有“VAR级别”的智能辅助。

关注 Coovally AI Hub,探索AI+体育更多可能!后台回复关键词「足球追踪」,获取完整源码与平台体验通道。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么要用AI辅助足球判罚?
  • 二、传统流程:从零搭建一个YOLO足球追踪系统
    • 数据采集与标注
    • 微调YOLO模型
    • 目标追踪机制详解
    • 什么是目标追踪?
    • ✅ 颜色聚类辅助身份识别
    • DeepSORT集成
    • 动态边框与行为分析
    • 球员分割
    • 球轨迹插值
  • 三、这些流程的“痛点”
  • 四、对比总结表格
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档