实用脚本如何分析球员跑动热点图?

wen 实用脚本 2

本文目录导读:

实用脚本如何分析球员跑动热点图?

  1. 方案一:基于公开事件数据的静态热点图(最常用、最准确)
  2. 方案二:基于视频追踪的半自动脚本(进阶与实用场景)
  3. 关键点:如何将数据变成真正有用的“跑动方向”?
  4. 总结与实用建议

分析球员跑动热点图(Heatmap)通常涉及数据获取坐标映射可视化三个核心步骤,由于国际足联(FIFA)和主流联赛的官方追踪数据(如STATS、Opta)多为商业机密,普通开发者常用公开的赛事数据计算机视觉(CV)来生成。

以下提供一个从零开始的实用脚本分析方案,涵盖基于公开数据(如StatsBomb)基于视频(半自动)两种主流路径。

基于公开事件数据的静态热点图(最常用、最准确)

这是最推荐的方案,如果你能获取到包含X/Y坐标的事件数据(例如StatsBomb的公开数据集),脚本会非常简单。

适用场景:赛后分析、战术复盘。 核心库pandas(数据处理)、matplotlib + mplsoccer(足球场绘图)。

环境准备

pip install pandas matplotlib mplsoccer

核心脚本逻辑

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mplsoccer import Pitch, VerticalPitch
# --- 假设你已加载数据:DataFrame包含 [player_name, x, y, type] ---
# 数据来源可以是 StatsBomb 开源数据 或 你自己抓取的坐标数据
# df = pd.read_csv('match_events.csv')
def analyze_heatmap(df, player_name='某球员'):
    # 1. 数据过滤:筛选目标球员的所有触球/跑动事件(通常排除门将)
    player_df = df[(df['player_name'] == player_name) & (df['type'] != 'Goal')]
    if player_df.empty:
        print(f"未找到球员 {player_name} 的数据")
        return
    # 2. 数据清洗:过滤异常的坐标点(通常在0-120,0-80之间)
    player_df = player_df[(player_df['x'] >= 0) & (player_df['x'] <= 120) &
                          (player_df['y'] >= 0) & (player_df['y'] <= 80)]
    # 3. 绘制球场和热力图
    pitch = Pitch(pitch_type='statsbomb', pitch_color='grass', line_color='white',
                  stripe=True)  # 使用 StatsBomb 标准球场
    fig, ax = pitch.draw(figsize=(12, 8))
    # 关键点:使用 KDE 核密度估计来生成平滑的热力图
    # 注意:kdeplot 的 x, y 坐标需要转换比例(StatsBomb的x最大120,y最大80)
    sns.kdeplot(
        data=player_df[['x', 'y']],
        x='x', y='y',  # 或者使用 x='x', y='y'
        ax=ax,
        fill=True,      # 填充颜色
        cmap='hot',     # 使用热度色系,如 'hot', 'inferno', 'plasma'
        levels=50,      # 等高线密度
        thresh=0.05,    # 过滤掉低于5%密度的区域,让图更干净
        alpha=0.8,
        bw_adjust=0.8   # 带宽调整,数值越小越尖锐,越大越平滑
    )
    # 4. 标注球员名字
    ax.set_title(f'{player_name} Run Heatmap', fontsize=16, fontweight='bold')
    # 5. 保存图片
    plt.savefig(f'heatmap_{player_name}.png', dpi=300, bbox_inches='tight')
    plt.show()
    print(f"热点图已保存为 heatmap_{player_name}.png")
# 示例调用
# analyze_heatmap(df, 'Lionel Messi')

核心点解析

  • Pitch 对象mplsoccer库自带了球场绘制,无需手动画线。
  • kdeplot:这是生成热力图的关键函数,它将离散的跑动坐标点转换为连续的概率密度分布,红色表示高频活动区域。
  • 坐标系转换:StatsBomb数据用的是x: 0-120y: 0-80

基于视频追踪的半自动脚本(进阶与实用场景)

如果你没有官方数据,只有比赛录像,就需要用目标跟踪(如YOLO)来完成。

适用场景:业余联赛分析、无法拿到转播数据的比赛。 核心库opencv-pythonultralytics(YOLOv8)、numpy

脚本思路:这比方案一复杂得多,这里给出简化的流程骨架:

import cv2
from ultralytics import YOLO
import numpy as np
# 1. 加载预训练模型(需训练或下载能识别足球球员的权重)
model = YOLO('yolov8x.pt') 
def video_to_heatmap(video_path, target_player_id=1):
    cap = cv2.VideoCapture(video_path)
    positions = []  # 存储坐标
    # 2. 需要在视频第一帧手动选定你要分析的球员
    ret, frame = cap.read()
    bbox = cv2.selectROI("Select Player", frame)  # 手动框选目标球员
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        # 3. 将裁剪区域送入模型或使用光流法跟踪
        # 简易方法:使用模板匹配或均值漂移(CamShift)
        # 复杂方法:每帧检测所有球员,通过IoU匹配ID
        # 伪代码:假设拿到该球员中心点坐标 (cx, cy)
        # positions.append((cx, cy))
        # 4. 透视变换(可选):将像素坐标映射到2D战术板的球场坐标
        # 这一步需要利用球场四条边线或角球点建立单应性矩阵
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    # 5. 将收集的像素坐标转换为2D平面坐标后,使用相同的 kdeplot 绘制
    # 注意:这里的坐标尺度可能不是0-120,需要归一化
    cap.release()
    cv2.destroyAllWindows()

关键点:如何将数据变成真正有用的“跑动方向”?

单纯的静态热力图只能显示活动范围,如果希望展示跑动方向,建议叠加箭头轨迹线

增强脚本建议

  • 增加时间戳:如果数据包含时间,可以按时间排序,用线连接坐标点,并在头部画箭头,即可生成“跑动轨迹图”。
  • 区分攻防:判断当球在前场时和在后场时,球员的坐标分布,分别生成“防守热力图”和“进攻热力图”,对比分析。
  • 速度指标:如果数据频率高(如25Hz),计算相邻两帧的距离差与时间差,得出速度,并过滤出冲刺时的坐标点来画图,用于分析高强跑动。

总结与实用建议

  1. 优先找数据:如果你是做实用分析,先想想哪里能拿到带坐标的数据。StatsBomb开源数据是目前最好用的免费资源,支持英超、西甲、世界杯等。
  2. 不建议视频识别:除非你有极强的CV背景,否则从视频还原坐标精度极低且耗时巨大,不适合日常分析。
  3. 可视化细节
    • 推荐使用 cmap='viridis'(色盲友好)或者 cmap='plasma'
    • 建议将 thresh 参数调高一些(0.1),可以去除噪音,让有意义的“热点”更突出。
    • 如果分析守门员,记得单独处理球场禁区范围。

如果你能提供具体的数据格式示例(比如有哪些列),我可以帮你写出完全适配的、可以直接跑通的完整代码。

抱歉,评论功能暂时关闭!