本文目录导读:

- 方案 A:如果你有原始比赛视频/热力图数据(半自动标注脚本)
- 方案 B:如果你有现成的XML/JSON数据(如Wyscout或StatsBomb)
- 方案 C:如果你只需要 纯计算脚本(最简单)
- 使用建议(关键的临门一脚)
要统计“门前抢点射门次数”並进行对比,你需要先定义清楚什么是门前抢点射门(通常指在小禁区或点球点附近,不调整直接触球射门,如铲射、垫射、头球冲顶)。
由于你提到“脚本”,下面我提供两种最实用的方案: 方案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)
这是最专业、最实用的脚本,假设你导出了比赛事件数据,其中包含每个射门的x,y坐标(通常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)
使用建议(关键的临门一脚)
-
定义权重:在足球战术分析中,“门前抢点”通常定义为:
- 射门位置在 球门区(小禁区) 内或点球点附近。
- 触球时间短(通常是第一脚触球直接射门,不停球)。
- 面对防守压迫(但这很难用脚本自动判断,通常靠人工标注)。
-
输出可视化:推荐在统计后,生成一个简单的柱状图对比(用
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是基础框架。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播