Как AI помогает автоматизировать спортивную статистику?
Ручная разметка спортивной статистики — узкое место для клубов и студий. Каждый матч требует 8–12 часов работы видеоаналитика, а стоимость лицензий профессиональных систем (например, Hawk-Eye) составляет десятки тысяч долларов. Мы разрабатываем AI-системы, которые по обычному видео с 2–4 камер выдают 80–90% точности профессиональных систем за долю стоимости — наши решения обходятся в разы дешевле. Типичные ошибки ручной разметки — пропуски эпизодов, субъективная оценка владения, расхождение в подсчёте пробега до 15%. AI лишён этих проблем: он обрабатывает каждый кадр, фиксируя координаты всех игроков и мяча. Ниже — технические детали: как мы вычисляем метрики и строим решения под ключ.
Как AI вычисляет пробег и скорость?
Для расчёта расстояний, скорости и тепловых карт мы используем трекинг игроков от YOLOv8 + ByteTrack. Класс SportsStatisticsEngine агрегирует данные по каждому игроку в режиме реального времени.
import numpy as np from collections import defaultdict from dataclasses import dataclass, field from typing import Optional @dataclass class PlayerStats: player_id: int team: str distance_m: float = 0.0 sprint_count: int = 0 # спринты > 25 км/ч max_speed_kmh: float = 0.0 touches: int = 0 shots: int = 0 passes_attempted: int = 0 passes_completed: int = 0 heatmap: np.ndarray = field(default_factory=lambda: np.zeros((68, 105))) class SportsStatisticsEngine: def __init__(self, fps: float, sport: str = 'football'): self.fps = fps self.sport = sport self.player_stats: dict[int, PlayerStats] = {} self.possession_log = [] # (frame_idx, team_with_ball) self.event_log = [] # Пороги скорости (м/с на кадр → км/ч) self.sprint_threshold = 25 / 3.6 / fps # м/кадр self.jogging_threshold = 11 / 3.6 / fps def update(self, frame_idx: int, tracked_players: list, ball_pos: Optional[tuple]): for player in tracked_players: pid = player['track_id'] team = player.get('team', 'unknown') pos = player.get('field_pos') if pid not in self.player_stats: self.player_stats[pid] = PlayerStats( player_id=pid, team=team ) stats = self.player_stats[pid] # Расстояние и скорость if hasattr(stats, '_prev_pos') and stats._prev_pos and pos: dist = np.sqrt((pos[0]-stats._prev_pos[0])**2 + (pos[1]-stats._prev_pos[1])**2) stats.distance_m += dist # Скорость в км/ч speed_ms = dist * fps speed_kmh = speed_ms * 3.6 if speed_kmh > stats.max_speed_kmh: stats.max_speed_kmh = speed_kmh if speed_kmh > 25: stats.sprint_count += 1 stats._prev_pos = pos # Тепловая карта if pos: hm_x = int(np.clip(pos[0], 0, 104)) hm_y = int(np.clip(pos[1], 0, 67)) stats.heatmap[hm_y, hm_x] += 1 # Владение мячом if ball_pos: possessing_team = self._determine_possession( ball_pos, tracked_players ) self.possession_log.append((frame_idx, possessing_team)) def _determine_possession(self, ball_pos: tuple, players: list) -> Optional[str]: """Ближайший игрок к мячу = владеет мячом""" if not players or not ball_pos: return None min_dist = float('inf') possessing_team = None for player in players: pos = player.get('field_pos') if pos is None: continue dist = np.sqrt((ball_pos[0]-pos[0])**2 + (ball_pos[1]-pos[1])**2) if dist < min_dist: min_dist = dist possessing_team = player.get('team') # Игрок ближе 2м = владеет return possessing_team if min_dist < 2.0 else None def compute_possession_stats(self) -> dict: total = len(self.possession_log) if total == 0: return {'team_a': 50.0, 'team_b': 50.0} counts = defaultdict(int) for _, team in self.possession_log: if team: counts[team] += 1 contested = total - sum(counts.values()) return { team: round(count / total * 100, 1) for team, count in counts.items() } def generate_match_report(self) -> dict: report = { 'possession': self.compute_possession_stats(), 'players': {} } for pid, stats in self.player_stats.items(): report['players'][pid] = { 'team': stats.team, 'distance_km': round(stats.distance_m / 1000, 2), 'sprint_count': stats.sprint_count, 'max_speed_kmh': round(stats.max_speed_kmh, 1), 'shots': stats.shots, 'passes_attempted': stats.passes_attempted, 'pass_accuracy': (stats.passes_completed / max(stats.passes_attempted, 1) * 100) } return report Как AI определяет владение мячом?
Метод _determine_possession вычисляет ближайшего игрока к мячу на каждом кадре. Если расстояние меньше 2 метров, фиксируется владение. Это проще и быстрее, чем геометрические методы, и даёт ±3–5% точности относительно Hawk-Eye.
Текстовые отчёты
После численных метрик мы генерируем аналитический текст через LLM — например, Mistral 7B. Промпт настраивается под формат спортивных бюллетеней. Для реализации используем Hugging Face Transformers.
from transformers import pipeline class MatchReportGenerator: def __init__(self): # GPT или локальная LLM для генерации текстового отчёта self.generator = pipeline('text-generation', model='mistralai/Mistral-7B-Instruct-v0.2', device=0) def generate_narrative(self, stats: dict, match_info: dict) -> str: prompt = f"""Сгенерируй краткий аналитический отчёт матча. Матч: {match_info['team_a']} vs {match_info['team_b']} Счёт: {match_info['score']} Владение: {stats['possession']} Топ по пробегу: {self._top_runners(stats['players'])} Удары по воротам: {sum(p['shots'] for p in stats['players'].values())} Напиши профессиональный аналитический текст на 3-4 предложения.""" result = self.generator(prompt, max_new_tokens=200, temperature=0.7, do_sample=True) return result[0]['generated_text'].split(prompt)[-1].strip() Почему AI-статистика выгоднее традиционных решений?
AI-система требует в 5–10 раз меньше вложений, чем лицензия Hawk-Eye, и обрабатывает данные быстрее человека. Мы реализовали более 15 проектов для футбольных клубов и студий, и гарантируем точность не менее 80% по ключевым метрикам. Если результаты оказываются ниже, мы дообучаем модель бесплатно. Точность AI-статистики по сравнению с профессиональными системами:
| Метрика | AI по видео | Hawk-Eye/Opta |
|---|---|---|
| Пробег игрока (ошибка) | ±5–8% | ±1–2% |
| Владение мячом | ±3–5% | ±1% |
| Количество ударов | ±10–15% | ±2% |
| Определение паса | ±15–20% | ±3% |
| Максимальная скорость | ±8–12% | ±2% |
Для любительских и полупрофессиональных соревнований — вполне достаточно. Для профессиональных лиг — дополнительные камеры и калибровка повышают точность до приемлемого уровня.
В одном из проектов мы развернули систему для клуба второй лиги: 4 IP-камеры 1080p, сервер с RTX 4060, обучение заняло 2 недели. После внедрения время анализа матча сократилось с 10 часов до 30 минут, а точность по пробегу составила 87% против ручной разметки. Клуб сэкономил порядка десятков тысяч долларов в год на услугах видеоаналитиков.
Как мы гарантируем точность?
Мы используем MLOps-практики: версионирование моделей через MLflow, A/B-тестирование на реальных матчах, мониторинг дрейфа данных. Каждый клиент получает отчёт о точности на его данных. Многолетний опыт и более 15 реализованных проектов позволяют браться за задачи любой сложности. Мы гарантируем, что итоговая точность будет не ниже заявленной — в противном случае дорабатываем модель бесплатно.
Процесс внедрения
- Аналитика — изучение условий съёмки, количества камер, требований к метрикам.
- Проектирование — выбор архитектуры (YOLO + ByteTrack + LLM), подготовка данных.
- Обучение и калибровка — дообучение модели под конкретный стадион, разметка тестовых эпизодов.
- Интеграция — развёртывание API, дашборда, настройка вебхуков.
- Тестирование — сравнение с ручной разметкой, оптимизация latency p99.
- Деплой — установка на сервер или облако, обучение операторов.
На каждом этапе мы используем MLOps-практики: версионирование моделей через MLflow, A/B-тестирование, мониторинг дрейфа данных. Это позволяет быстро адаптироваться под изменения в условиях съёмки.
Что входит в проект
- Обученная модель детекции и трекинга
- REST API для получения статистики в реальном времени
- Дашборд (визуализация метрик, тепловые карты, отчёты)
- Интеграция с существующей инфраструктурой
- Документация по эксплуатации и API
- Обучение операторов (2 часа); техподдержка 3 месяца
Сроки ориентировочно
| Тип проекта | Срок |
|---|---|
| Базовая статистика (пробег + владение + тепловая карта) | 4–7 недель |
| Полная статистическая платформа (с текстовыми отчётами и API) | 8–14 недель |
| Добавление нового вида спорта | 2–4 недели |
Получите консультацию по вашему проекту — мы оценим сложность и точность на ваших данных. Закажите пилотный проект и увидите результаты через 4 недели.







