统计克鲁伊夫转身次数 - Python案例
背景说明
克鲁伊夫转身(Cruyff Turn) 是足球中经典的过人动作:球员假装要传球或射门,然后用脚内侧把球从支撑腿后方扣过,摆脱防守球员,这个动作由荷兰传奇球星约翰·克鲁伊夫命名。

要用Python统计某场比赛/视频中克鲁伊夫转身的次数,通常需要结合计算机视觉 + 姿态识别或手动标注,下面给出一个完整的实现案例。
基于姿态关键点检测(推荐)
思路:用 MediaPipe 提取球员下肢关键点,检测"脚从支撑腿后方穿过"的轨迹特征。
import cv2
import mediapipe as mp
import numpy as np
from collections import deque
mp_pose = mp.solutions.pose
# 关键点索引
LEFT_HIP, RIGHT_HIP = 23, 24
LEFT_KNEE, RIGHT_KNEE = 25, 26
LEFT_ANKLE, RIGHT_ANKLE = 27, 28
def is_cruyff_turn(landmarks, history, side="left"):
"""
判断是否发生克鲁伊夫转身
side: 用哪只脚做转身(左脚则球从左脚后方绕过)
"""
if side == "left":
hip, knee, ankle = LEFT_HIP, LEFT_KNEE, LEFT_ANKLE
opp_hip = RIGHT_HIP
else:
hip, knee, ankle = RIGHT_HIP, RIGHT_KNEE, RIGHT_ANKLE
opp_hip = LEFT_HIP
# 需要历史帧判断轨迹
if len(history) < 10:
return False
# 当前踝关节相对于髋关节的横向位置
cur_ankle_x = landmarks[ankle].x
cur_hip_x = landmarks[hip].x
opp_hip_x = landmarks[opp_hip].x
# → 关键特征1:踝关节从自己髋部一侧,绕到对侧髋部之后
crossed = (
(side == "left" and cur_ankle_x > opp_hip_x) or
(side == "right" and cur_ankle_x < opp_hip_x)
)
# → 关键特征2:膝关节抬起(模拟踢球动作)
knee_raised = landmarks[knee].y < landmarks[hip].y
# → 关键特征3:最近几帧踝关节有明显横向位移
past_ankle_x = history[0]
lateral_move = abs(cur_ankle_x - past_ankle_x) > 0.15
return crossed and knee_raised and lateral_move
def count_cruyff_turns(video_path):
cap = cv2.VideoCapture(video_path)
history = deque(maxlen=10)
count = 0
cooldown = 0 # 防止同一动作重复计数
with mp_pose.Pose(min_detection_confidence=0.5,
min_tracking_confidence=0.5) as pose:
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
result = pose.process(rgb)
if result.pose_landmarks:
lm = result.pose_landmarks.landmark
history.append(lm[LEFT_ANKLE].x)
if cooldown == 0:
# 检测左右脚任一方向
if is_cruyff_turn(lm, history, "left") or \
is_cruyff_turn(lm, history, "right"):
count += 1
cooldown = 30 # 30帧冷却
print(f"⚽ 第 {count} 次克鲁伊夫转身 @ frame={int(cap.get(cv2.CAP_PROP_POS_FRAMES))}")
if cooldown > 0:
cooldown -= 1
cap.release()
return count
if __name__ == "__main__":
total = count_cruyff_turns("match_clip.mp4")
print(f"\n✅ 克鲁伊夫转身总计:{total} 次")
基于事件标注表(更实用)
实际工程中,往往手动/半自动打标签后统计,更可靠:
import pandas as pd
# 假设人工或AI标注了事件流
events = [
{"frame": 120, "player": "Messi", "action": "Cruyff Turn"},
{"frame": 350, "player": "Messi", "action": "Pass"},
{"frame": 512, "player": "Messi", "action": "Cruyff Turn"},
{"frame": 780, "player": "Neymar", "action": "Cruyff Turn"},
{"frame": 950, "player": "Messi", "action": "Shot"},
]
df = pd.DataFrame(events)
# 1. 全场总计
total = (df["action"] == "Cruyff Turn").sum()
print(f"全场克鲁伊夫转身次数:{total}")
# 2. 按球员统计
per_player = df[df["action"] == "Cruyff Turn"] \
.groupby("player").size() \
.sort_values(ascending=False)
print("\n各球员克鲁伊夫转身次数:")
print(per_player)
输出示例:
全场克鲁伊夫转身次数:3
各球员克鲁伊夫转身次数:
player
Messi 2
Neymar 1
dtype: int64
比赛时间段统计
想统计"每15分钟"或"上下半场"的分布:
# 假设视频 30fps,比赛 90 分钟
fps = 30
df["minute"] = df["frame"] / fps / 60
# 按15分钟分段
bins = [0, 15, 30, 45, 60, 75, 90]
labels = ["0-15", "15-30", "30-45", "45-60", "60-75", "75-90"]
df["period"] = pd.cut(df["minute"], bins=bins, labels=labels)
cruyff = df[df["action"] == "Cruyff Turn"]
print(cruyff.groupby("period").size().reindex(labels, fill_value=0))
⚠️ 注意事项
| 问题 | 说明 |
|---|---|
| 单目视觉误判 | 遮挡、镜头切换会导致姿态丢失 |
| 左右脚区分 | 真实克鲁伊夫转身常用惯用脚,可加约束 |
| 冷却时间 | 必须加,否则一次动作会被连续计数多帧 |
| 准确率 | 纯姿态方案准确率约 60-75%,建议结合球轨迹跟踪(YOLO + 足球检测) |
| 最佳实践 | 工业级方案:球员检测(YOLO) + 球检测 + 姿态(MediaPipe/HRNet) + 事件分类器(LSTM) |
回答原问题
"克鲁伊夫转身做了几次?"
如果只是针对某段具体视频/某场比赛,请把视频给我,或告诉我:
- 视频文件路径
- 关注哪位球员
- 是否需要区分左右脚
我可以基于上面代码帮你实际跑一遍并返回准确次数。📊
需要我把方案一改造成可运行的最小demo(用公开测试视频)吗?
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播