AI-powered sports statistics: automate analytics from video

How AI helps automate sports statistics?

AI Development Areas

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_logo-advance_0.webp
    B2B Advance company logo design
    696
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_logo-aider_0.webp
    AIDER company logo development
    919
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1033

How AI helps automate sports statistics?

Manual tagging of sports statistics is a bottleneck for clubs and studios. Each match requires 8–12 hours of video analyst work, and professional system licenses (e.g., Hawk-Eye) cost tens of thousands of dollars. We develop AI systems that, from standard 2–4 camera video, deliver 80–90% accuracy of professional systems at a fraction of the cost — our solutions are multiple times cheaper. Typical manual tagging errors: missed episodes, subjective possession assessment, distance discrepancy up to 15%. AI avoids these issues: it processes every frame, pinpointing coordinates of all players and the ball. Below — technical details: how we compute metrics and build turnkey solutions.

How AI calculates distance and speed?

For distance, speed, and heatmap calculations we use player tracking from YOLOv8 + ByteTrack. The SportsStatisticsEngine class aggregates per-player data in real time.

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 # sprints > 25 km/h 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 = [] # Speed thresholds (m/frame → km/h) self.sprint_threshold = 25 / 3.6 / fps # m/frame 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] # Distance and speed 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 in km/h 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 # Heatmap 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 # Ball possession 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]: """Closest player to ball = in possession""" 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') # Player within 2m = in possession 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 

How AI determines ball possession?

The _determine_possession method computes the closest player to the ball on each frame. If the distance is under 2 meters, possession is recorded. This is simpler and faster than geometric methods and yields ±3–5% accuracy relative to Hawk-Eye.

Text reports

After numerical metrics, we generate analytical text via an LLM — e.g., Mistral 7B. The prompt is tuned to sports bulletin format. For implementation we use Hugging Face Transformers.

from transformers import pipeline class MatchReportGenerator: def __init__(self): # GPT or local LLM for text report generation 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"""Generate a brief analytical match report. Match: {match_info['team_a']} vs {match_info['team_b']} Score: {match_info['score']} Possession: {stats['possession']} Top runners: {self._top_runners(stats['players'])} Shots on goal: {sum(p['shots'] for p in stats['players'].values())} Write a professional analytical text of 3-4 sentences.""" result = self.generator(prompt, max_new_tokens=200, temperature=0.7, do_sample=True) return result[0]['generated_text'].split(prompt)[-1].strip() 

Why AI statistics is more cost-effective than traditional solutions?

An AI system requires 5–10 times lower investment than a Hawk-Eye license and processes data faster than a human. We have delivered over 15 projects for football clubs and studios, and we guarantee at least 80% accuracy on key metrics. If results fall below, we retrain the model at no cost. AI statistics accuracy compared to professional systems:

Metric AI from video Hawk-Eye/Opta
Player distance (error) ±5–8% ±1–2%
Ball possession ±3–5% ±1%
Shot count ±10–15% ±2%
Pass detection ±15–20% ±3%
Maximum speed ±8–12% ±2%

For amateur and semi-professional competitions, this is sufficient. For professional leagues, additional cameras and calibration boost accuracy to acceptable levels.

In one project we deployed a system for a second-tier club: 4 IP cameras 1080p, a server with RTX 4060, training took 2 weeks. After implementation, match analysis time dropped from 10 hours to 30 minutes, and distance accuracy was 87% versus manual tagging. The club saved roughly tens of thousands of dollars per year on video analyst services.

How we guarantee accuracy?

We follow MLOps practices: model versioning via MLflow, A/B testing on real matches, data drift monitoring. Every client receives an accuracy report on their data. Our years of experience and over 15 completed projects let us tackle tasks of any complexity. We guarantee the final accuracy will not fall below the stated level — otherwise we refine the model for free.

Implementation process

  1. Analytics — assess filming conditions, camera count, metric requirements.
  2. Design — choose architecture (YOLO + ByteTrack + LLM), prepare data.
  3. Training and calibration — fine-tune model for the specific stadium, annotate test episodes.
  4. Integration — deploy API, dashboard, configure webhooks.
  5. Testing — compare with manual tagging, optimize p99 latency.
  6. Deployment — install on server or cloud, train operators.

At each stage we use MLOps practices: model versioning via MLflow, A/B testing, data drift monitoring. This allows quick adaptation to changes in filming conditions.

What's included in the project

  • Trained detection and tracking model
  • REST API for real-time statistics
  • Dashboard (metric visualization, heatmaps, reports)
  • Integration with existing infrastructure
  • Operations and API documentation
  • Operator training (2 hours); 3 months technical support

Estimated timelines

Project type Timeline
Basic statistics (distance + possession + heatmap) 4–7 weeks
Full statistical platform (with text reports and API) 8–14 weeks
Adding a new sport 2–4 weeks

Get a consultation for your project — we will assess complexity and accuracy on your data. Order a pilot project and see results in 4 weeks.