实用脚本统计冲刺跑次数谁更多?

wen 实用脚本 3

统计冲刺跑次数脚本

你想统计两段视频/两个运动员的冲刺跑次数对比,下面给你一个可运行的 Python 脚本,用 OpenCV 分析视频中人物的移动速度来判定冲刺。

实用脚本统计冲刺跑次数谁更多?

基于视频运动速度(通用)

import cv2
import numpy as np
from collections import deque
def count_sprints(video_path, speed_threshold=15, min_duration=5, 
                  roi=None, scale=0.5, show=False):
    """
    统计视频中冲刺跑次数。
    参数:
        video_path     : 视频文件路径
        speed_threshold: 触发冲刺的像素位移阈值(每帧)
        min_duration   : 连续超过阈值的最小帧数才算一次冲刺
        roi            : (x, y, w, h) 感兴趣区域,None 表示全图
        scale          : 缩放比例,加速处理
        show           : 是否显示检测过程
    返回:
        冲刺次数
    """
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        raise IOError(f"无法打开视频: {video_path}")
    # 背景减除器
    bg = cv2.createBackgroundSubtractorMOG2(history=200, varThreshold=25, detectShadows=False)
    prev_center = None
    over_count = 0          # 连续超阈值帧数
    sprint_count = 0
    speeds = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        if scale != 1.0:
            frame = cv2.resize(frame, None, fx=scale, fy=scale)
        if roi:
            x, y, w, h = [int(v * scale) for v in roi]
            frame = frame[y:y+h, x:x+w]
        fg = bg.apply(frame)
        fg = cv2.morphologyEx(fg, cv2.MORPH_OPEN, np.ones((5,5), np.uint8))
        fg = cv2.dilate(fg, np.ones((7,7), np.uint8), iterations=2)
        contours, _ = cv2.findContours(fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        if not contours:
            prev_center = None
            continue
        # 取最大轮廓作为人物
        c = max(contours, key=cv2.contourArea)
        if cv2.contourArea(c) < 300:
            continue
        M = cv2.moments(c)
        if M["m00"] == 0:
            continue
        cx = int(M["m10"] / M["m00"])
        cy = int(M["m01"] / M["m00"])
        if prev_center is not None:
            speed = np.hypot(cx - prev_center[0], cy - prev_center[1])
            speeds.append(speed)
            if speed > speed_threshold:
                over_count += 1
                if over_count == min_duration:   # 达标瞬间记 1 次
                    sprint_count += 1
            else:
                over_count = 0
        prev_center = (cx, cy)
        if show:
            cv2.circle(frame, (cx, cy), 8, (0,0,255), -1)
            cv2.putText(frame, f"Sprints: {sprint_count}", (10, 30),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)
            cv2.imshow("Sprint Detection", frame)
            if cv2.waitKey(1) & 0xFF == 27:
                break
    cap.release()
    if show:
        cv2.destroyAllWindows()
    avg_speed = float(np.mean(speeds)) if speeds else 0
    return sprint_count, avg_speed
if __name__ == "__main__":
    # 对比两个视频
    videos = {
        "运动员A": "video_A.mp4",
        "运动员B": "video_B.mp4",
    }
    results = {}
    for name, path in videos.items():
        n, avg = count_sprints(path, speed_threshold=15, min_duration=5, scale=0.5)
        results[name] = n
        print(f"{name}: 冲刺 {n} 次 (平均速度 {avg:.1f} px/帧)")
    winner = max(results, key=results.get)
    print(f"\n🏆 冲刺次数更多:{winner} ({results[winner]} 次)")

使用:

pip install opencv-python numpy
python sprint_count.py

带坐标数据(如果你有 GPS / 追踪数据)

如果已有逐帧坐标,更精准:

import pandas as pd
import numpy as np
def count_sprints_from_tracking(df, speed_threshold=7.0, min_duration_s=1.0, fps=30):
    """
    df 需要列: x, y  (米)  —— 可选: t
    冲刺定义: 速度 > threshold 且持续 >= min_duration_s 秒
    """
    dx = df["x"].diff()
    dy = df["y"].diff()
    speed = np.hypot(dx, dy) * fps          # m/s
    is_sprint = speed > speed_threshold
    sprint_count = 0
    streak = 0
    min_frames = int(min_duration_s * fps)
    for s in is_sprint:
        if s:
            streak += 1
        else:
            if streak >= min_frames:
                sprint_count += 1
            streak = 0
    if streak >= min_frames:
        sprint_count += 1
    return sprint_count, speed.mean(), speed.max()

关键参数调优建议

参数 说明 建议
speed_threshold 判定为冲刺的每帧位移 先跑一次打印 speeds 分布,取 85~90 分位数
min_duration 持续帧数(防误报) 30fps 视频建议 5~15 帧(0.2~0.5s)
scale 缩小处理加速 5 一般够用
roi 只关注跑道区域 排除观众/教练干扰

更专业的替代方案

  • YOLOv8 + ByteTrack 做人员跟踪,再对 track_id 的轨迹算速度(多人场景必备)
  • Sprint 判定运动学惯例:速度 > 7 m/s(≈25 km/h)且持续 > 1 s 视为一次冲刺(可参考 FIFA / Catapult 标准)

如果需要多目标(同时追踪多名运动员) 或 接入 YOLO 追踪 的版本,告诉我你的视频场景(单/多人、是否固定机位),我可以直接给你完整代码。

上一篇综合实用脚本,AI预测的准确率能达到多少?

下一篇当前分类已是最新一篇

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