实用脚本统计门前抢点射门次数对比?

wen 实用脚本 4

本文目录导读:

实用脚本统计门前抢点射门次数对比?

  1. 方案 A:如果你有原始比赛视频/热力图数据(半自动标注脚本)
  2. 方案 B:如果你有现成的XML/JSON数据(如Wyscout或StatsBomb)
  3. 方案 C:如果你只需要 纯计算脚本(最简单)
  4. 使用建议(关键的临门一脚)

要统计“门前抢点射门次数”並进行对比,你需要先定义清楚什么是门前抢点射门(通常指在小禁区或点球点附近,不调整直接触球射门,如铲射、垫射、头球冲顶)。

由于你提到“脚本”,下面我提供两种最实用的方案: 方案A:适用于足球比赛录像分析师(使用Python+OpenCV或半自动标注) 方案B:适用于撰写战术报告(使用Python处理已有的统计表格/JSON数据)

请根据你手头已有的数据格式选择。


方案 A:如果你有原始比赛视频/热力图数据(半自动标注脚本)

这个脚本不会自动识别(那需要AI模型),但会帮你快速批量标注和统计,你只需要在射门瞬间按一个键(如 P 代表抢点射门,N 代表非抢点),脚本自动记录时间戳、位置和类型,最后输出对比统计表。

import cv2
import pandas as pd
import numpy as np
import sys
# 定义门前区域(假设视频分辨率为1920x1080,根据实际调整比例)
# 门前抢点通常在球门区(小禁区)附近,即图像下方靠中间
VIDEO_PATH = "match.mp4"
DATA_FILE = "shooting_events.csv"
def define_key_point(x, y, frame_width, frame_height):
    """
    判断该射门是否属于门前抢点(这里简单以禁区中路的近距离区域为例)
    实际使用中,你应该通过点击球场模型来获取坐标。
    """
    # 假设门前区域为:宽度中间40%,高度下方30%(靠近镜头)
    central_x_start = frame_width * 0.30
    central_x_end = frame_width * 0.70
    bottom_y_start = frame_height * 0.70
    if central_x_start < x < central_x_end and y > bottom_y_start:
        return True  # 抢点
    return False
def manual_annotation():
    cap = cv2.VideoCapture(VIDEO_PATH)
    fps = cap.get(cv2.CAP_PROP_FPS)
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    events = []
    ret, frame = cap.read()
    if not ret:
        print("无法读取视频")
        return
    while ret:
        height, width = frame.shape[:2]
        display = frame.copy()
        cv2.putText(display, "P: 抢点射门 | N: 非抢点 | Q: 退出", (50, 50), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)
        cv2.imshow("标注模式", display)
        key = cv2.waitKey(0) & 0xFF
        if key == ord('p') or key == ord('P'):
            # 记录当前帧时间
            current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)
            timestamp = current_frame / fps
            # 这里简化处理:假设点击鼠标取点(真实代码应绑定鼠标回调)
            # 为了演示,我们固定给一个假坐标(实际要你自己选)
            mouse_x, mouse_y = width//2, height-100  # 假设在门前中路
            is_six_yard_box = define_key_point(mouse_x, mouse_y, width, height)
            if is_six_yard_box:
                shot_type = "抢点"
            else:
                shot_type = "非抢点"
            events.append({
                'time': timestamp,
                'frame': current_frame,
                'type': shot_type
            })
            print(f"记录:第{int(timestamp)}秒 - {shot_type}射门")
        if key == ord('n') or key == ord('N'):
            current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)
            timestamp = current_frame / fps
            events.append({
                'time': timestamp,
                'frame': current_frame,
                'type': "非抢点"
            })
            print(f"记录:第{int(timestamp)}秒 - 非抢点射门")
        if key == ord('q'):
            break
        # 按空格暂停/继续,按右箭头跳帧(这里简化为下一帧)
        if key == 27:  # ESC
            break
        # 跳到下一帧(实际可加入快进逻辑)
        ret, frame = cap.read()
    cap.release()
    cv2.destroyAllWindows()
    # 保存为CSV
    df = pd.DataFrame(events)
    df.to_csv(DATA_FILE, index=False)
    print("数据已保存至", DATA_FILE)
    return df
def analyze_and_compare(df):
    if df.empty:
        return
    # 统计总数
    total_shots = len(df)
    poaching_shots = len(df[df['type'] == '抢点'])
    non_poaching_shots = total_shots - poaching_shots
    print("\n========== 门前抢点射门对比统计 ==========")
    print(f"总射门次数: {total_shots}")
    print(f"门前抢点射门: {poaching_shots} 次 ({poaching_shots/total_shots*100:.1f}%)")
    print(f"非抢点射门: {non_poaching_shots} 次 ({non_poaching_shots/total_shots*100:.1f}%)")
    # 对比进球率(假设你还需要输入进球标记,这里简化)
    # 你可以扩展成:是否进球(1/0)
if __name__ == "__main__":
    df = manual_annotation()
    analyze_and_compare(df)

方案 B:如果你有现成的XML/JSON数据(如Wyscout或StatsBomb)

这是最专业、最实用的脚本,假设你导出了比赛事件数据,其中包含每个射门的xy坐标(通常0-100单位的相对坐标)和body_part(脚/头),门前抢点的定义通常是距离球门小于15码且射门动作是一次触球

import pandas as pd
import json
# 假设加载了一个包含所有射门事件的数据列表
# 数据格式:[(球员, 距离(米), 是否头球, 是否进球), ...]
# 或者从CSV加载
def load_data_from_csv(file_path):
    df = pd.read_csv(file_path)
    # 假设列名为:player, x, y, body_part, is_goal
    # x, y 是标准化后的位置 (通常0-100)
    return df
def filter_poaching_shots(df, threshold_distance=5.5):
    """
    根据位置定义门前抢点:
    通常球门位于 x=100, y=50 (以进攻方向为x轴)
    门前抢点:距离球门中心小于 5.5米(小禁区边缘),并且靠近中路
    """
    # 计算距离(这里简化,假设每条数据已经有distance_to_goal列)
    if 'distance_to_goal' not in df.columns:
        # 计算欧氏距离(归一化坐标)
        df['distance_to_goal'] = np.sqrt((df['x'] - 100)**2 + (df['y'] - 50)**2)
    poaching = df[df['distance_to_goal'] <= threshold_distance]
    non_poaching = df[df['distance_to_goal'] > threshold_distance]
    return poaching, non_poaching
def compare_statistics(df):
    # 定义抢点
    poaching, non_poaching = filter_poaching_shots(df)
    print(f"🏟️ 全队射门统计对比")
    print(f"{'指标':<15} {'门前抢点':<15} {'非抢点':<15}")
    print("-" * 45)
    # 射门总数
    total_poach = len(poaching)
    total_non_poach = len(non_poaching)
    print(f"{'射门次数':<15} {total_poach:<15} {total_non_poach:<15}")
    # 进球数
    goals_poach = poaching['is_goal'].sum() if 'is_goal' in poaching.columns else 0
    goals_non_poach = non_poaching['is_goal'].sum() if 'is_goal' in non_poaching.columns else 0
    print(f"{'进球数':<15} {goals_poach:<15} {goals_non_poach:<15}")
    # 转化率
    conv_poach = (goals_poach / total_poach * 100) if total_poach > 0 else 0
    conv_non_poach = (goals_non_poach / total_non_poach * 100) if total_non_poach > 0 else 0
    print(f"{'转化率 (%)':<15} {conv_poach:.1f}%{'':<10} {conv_non_poach:.1f}%")
    # 射正率
    if 'on_target' in df.columns:
        ont_poach = poaching['on_target'].mean() * 100
        ont_non = non_poaching['on_target'].mean() * 100
        print(f"{'射正率 (%)':<15} {ont_poach:.1f}%{'':<10} {ont_non:.1f}%")
    # 按球员对比
    print("\n👥 球员对比 (门前抢点次数)")
    if 'player' in df.columns:
        player_poach = poaching.groupby('player').size().sort_values(ascending=False)
        print(player_poach)
    else:
        print("数据中无球员字段,跳过球员对比")
# 示例使用
if __name__ == "__main__":
    # 模拟数据
    sample_data = {
        'player': ['A', 'B', 'C', 'A', 'B', 'D'],
        'x': [98, 99, 40, 95, 97, 30],
        'y': [50, 52, 60, 48, 51, 45],
        'is_goal': [1, 0, 0, 1, 0, 0],
        'on_target': [1, 1, 0, 1, 1, 0]
    }
    df = pd.DataFrame(sample_data)
    compare_statistics(df)

方案 C:如果你只需要 纯计算脚本(最简单)

def compare_poaching_shots(shots_list, poaching_threshold=10):
    """
    shots_list: 列表,每个元素为 (距离球门米数, 是否进球, 球员)
    计算门前(<=10米)抢点射门与远射的对比
    """
    p_shots = [s for s in shots_list if s[0] <= poaching_threshold]
    n_shots = [s for s in shots_list if s[0] > poaching_threshold]
    def calc(shots):
        total = len(shots)
        goals = sum(1 for s in shots if s[1] == 1)
        conversion = goals / total * 100 if total > 0 else 0
        return total, goals, conversion
    p_total, p_goals, p_conv = calc(p_shots)
    n_total, n_goals, n_conv = calc(n_shots)
    print("门前抢点射门: {}次, 进球{}个 (转化率{:.1f}%)".format(p_total, p_goals, p_conv))
    print("非抢点射门: {}次, 进球{}个 (转化率{:.1f}%)".format(n_total, n_goals, n_conv))
# 调用示例
data = [
    (3, 1, "前锋A"),  # 3米,进球
    (8, 0, "前锋B"),  # 8米,未进
    (25, 1, "中场C")  # 25米,远射进球
]
compare_poaching_shots(data)

使用建议(关键的临门一脚)

  1. 定义权重:在足球战术分析中,“门前抢点”通常定义为:

    • 射门位置在 球门区(小禁区) 内或点球点附近。
    • 触球时间短(通常是第一脚触球直接射门,不停球)。
    • 面对防守压迫(但这很难用脚本自动判断,通常靠人工标注)。
  2. 输出可视化:推荐在统计后,生成一个简单的柱状图对比(用 matplotlib),会更直观:

import matplotlib.pyplot as plt
import pandas as pd
# 假设有统计数据
data = {'射门类型': ['门前抢点', '非抢点'], '射门次数': [12, 30], '进球数': [4, 3]}
df = pd.DataFrame(data)
# 绘制双轴柱状图对比
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
df.plot(x='射门类型', y='射门次数', kind='bar', ax=ax1, color='blue', position=0, width=0.3)
df.plot(x='射门类型', y='进球数', kind='bar', ax=ax2, color='red', position=1, width=0.3)'门前抢点 vs 非抢点 - 射门与进球对比')
plt.show()

你需要哪个? 如果你的数据在Excel里,告诉我列名(如球员、位置、射门结果),我可以直接写一个读取Excel一键出报表的脚本,如果你手头是视频,方案A是基础框架。

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