统计"假动作晃过防守"次数的脚本方案
先说明:没有通用的现成脚本能直接统计"假动作",因为这需要识别动作语义,下面给你一套可落地的实现思路 + 可运行示例代码,按你的数据源选择。

先明确你的数据源(决定方案)
| 数据源 | 可行性 | 说明 |
|---|---|---|
| 手动标注视频(推荐入门) | 用脚本做计数+时长统计,人工打点 | |
| 姿态估计(MediaPipe/OpenPose) | 可识别变向、重心晃动,误报较多 | |
| 专业追踪数据(SportVU/Hawk-Eye) | 有坐标轨迹,可做速度/方向突变检测 | |
| 纯录像无标注 | 需训练动作识别模型,成本高 |
方案A:手动打点 + 脚本统计(最实用)
适合教练/分析师边看录像边按键标记。
# fake_move_counter.py
# 用法:播放视频时按 F 记录一次假动作,按 Q 退出,自动输出统计
import cv2, time, json, os
from datetime import datetime
VIDEO = "game.mp4"
OUT = "fake_move_log.json"
cap = cv2.VideoCapture(VIDEO)
fps = cap.get(cv2.CAP_PROP_FPS) or 30
records = []
frame_id = 0
print("按 F = 记录假动作 | 按 S = 撤销上一条 | 按 Q = 结束")
while True:
ret, frame = cap.read()
if not ret:
break
frame_id += 1
t = frame_id / fps
cv2.putText(frame, f"t={t:.1f}s count={len(records)}",
(20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
cv2.imshow("video", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('f'):
records.append({"time_sec": round(t,2), "frame": frame_id,
"wall": datetime.now().isoformat()})
print(f"[+] 记录 #{len(records)} @ {t:.1f}s")
elif key == ord('s') and records:
print(f"[-] 撤销 {records.pop()}")
elif key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# 输出统计
result = {
"video": VIDEO,
"total_fake_moves": len(records),
"events": records,
"intervals_sec": [round(records[i+1]["time_sec"]-records[i]["time_sec"],2)
for i in range(len(records)-1)]
}
with open(OUT, "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print(f"\n✅ 共 {len(records)} 次假动作,已保存 {OUT}")
优点:100%准确(人工判断);缺点:需人工观看。
方案B:姿态估计自动检测"变向/重心晃动"
用 MediaPipe 提取髋部/肩部关键点,检测短时间内横向速度反向作为假动作候选。
# auto_fake_move.py (需: pip install mediapipe opencv-python numpy)
import cv2, numpy as np, json
import mediapipe as mp
VIDEO = "game.mp4"
WINDOW = 8 # 平滑窗口(帧)
REVERSE_THRESH = 0.03 # 归一化横向速度反向阈值
MIN_GAP = 15 # 两次假动作最小间隔(帧)
mp_pose = mp.solutions.pose
cap = cv2.VideoCapture(VIDEO)
fps = cap.get(cv2.CAP_PROP_FPS) or 30
xs, frame_ids, events = [], [], []
with mp_pose.Pose(min_detection_confidence=0.5) as pose:
fid = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret: break
fid += 1
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
res = pose.process(rgb)
if res.pose_landmarks:
h = res.pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_HIP]
r = res.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_HIP]
xs.append((h.x + r.x) / 2)
frame_ids.append(fid)
x = np.array(xs)
if len(x) > WINDOW:
v = np.diff(x) # 横向速度
vs = np.convolve(v, np.ones(WINDOW)/WINDOW, 'same') # 平滑
last_event = -MIN_GAP
for i in range(1, len(vs)):
if vs[i-1] > REVERSE_THRESH and vs[i] < -REVERSE_THRESH:
if frame_ids[i] - last_event >= MIN_GAP:
events.append({"frame": frame_ids[i],
"time_sec": round(frame_ids[i]/fps, 2)})
last_event = frame_ids[i]
cap.release()
print(json.dumps({"total": len(events), "events": events},
ensure_ascii=False, indent=2))
注意:这是候选检测,含误报(正常变向也会触发),需人工复核或调阈值 REVERSE_THRESH。
方案C:如果有逐帧坐标数据(轨迹)
直接对 (x, y) 轨迹做方向突变检测,比姿态估计更准:
def count_fakes(traj_xy, fps=30, angle_thresh=60, min_disp=0.5):
"""traj_xy: [(x,y),...] 单位米;返回假动作候选时间点"""
import numpy as np
p = np.array(traj_xy)
v = np.diff(p, axis=0) * fps
speed = np.linalg.norm(v, axis=1)
angles = []
for i in range(1, len(v)):
a, b = v[i-1], v[i]
na, nb = np.linalg.norm(a), np.linalg.norm(b)
if na < min_disp or nb < min_disp: continue
cos = np.clip(np.dot(a,b)/(na*nb), -1, 1)
ang = np.degrees(np.arccos(cos))
if ang > angle_thresh:
angles.append(i/fps)
return angles
建议
- 先从方案A做起——脚本简单、结果可信,跑通流程。
- 需要自动化再上方案B/C,并保留人工复核环节。
- 若要做"假动作 vs 正常变向"的语义区分,最终需标注数据 + 训练分类模型(如 ST-GCN / SlowFast),不是几行脚本能解决的。
需要我针对你的具体数据格式(视频/CSV坐标/传感器)把脚本改写成可直接跑的版本吗?告诉我数据长什么样即可。
版权声明: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直播