Spaces:
Running
Running
import gradio as gr | |
import os | |
import numpy as np | |
from utils import read_video, save_video | |
from trackers import Tracker | |
from team_assigner import TeamAssigner | |
from player_ball_assigner import PlayerBallAssigner | |
from camera_movement_estimator import CameraMovementEstimator | |
from view_transformer import ViewTransformer | |
from speed_and_distance_estimator import SpeedAndDistance_Estimator | |
def process_video(input_video, player_stats=True, ball_stats=True): | |
print("input: " + input_video) | |
# Read Video | |
video_frames = read_video(input_video) # use the uploaded file | |
# Initialize Tracker | |
tracker = Tracker('models/best.pt') | |
if input_video.endswith("121364_0_small.mp4"): | |
print("loading cached tracks") | |
tracks = tracker.get_object_tracks(video_frames, | |
read_from_stub=True, | |
stub_path='stubs/track_stub_121364_0_small.pkl') | |
else: | |
tracks = tracker.get_object_tracks(video_frames) | |
# Interpolate Ball Positions | |
tracks["ball"] = tracker.interpolate_ball_positions(tracks["ball"]) | |
# Get object positions | |
tracker.add_position_to_tracks(tracks) | |
# Camera movement estimator | |
camera_movement_estimator = CameraMovementEstimator(video_frames[0]) | |
if input_video.endswith("121364_0_small.mp4"): | |
print("loading cached camera movements") | |
camera_movement_per_frame = camera_movement_estimator.get_camera_movement(video_frames, | |
read_from_stub=True, | |
stub_path='stubs/camera_movement_stub_121364_0_small.pkl') | |
else: | |
camera_movement_per_frame = camera_movement_estimator.get_camera_movement(video_frames) | |
camera_movement_estimator.add_adjust_positions_to_tracks(tracks, camera_movement_per_frame) | |
# View Transformer | |
view_transformer = ViewTransformer() | |
view_transformer.add_transformed_position_to_tracks(tracks) | |
# Speed and distance estimator | |
speed_and_distance_estimator = SpeedAndDistance_Estimator() | |
exclude_objects=['referees', 'players', 'ball'] | |
if player_stats: | |
exclude_objects.remove('players') | |
if ball_stats: | |
exclude_objects.remove('ball') | |
speed_and_distance_estimator.add_speed_and_distance_to_tracks(tracks, exclude_objects) | |
# Assign Player Teams | |
team_assigner = TeamAssigner() | |
team_assigner.assign_team_color(video_frames[0], tracks['players'][0]) | |
for frame_num, player_track in enumerate(tracks['players']): | |
for player_id, track in player_track.items(): | |
team = team_assigner.get_player_team(video_frames[frame_num], track['bbox'], player_id) | |
tracks['players'][frame_num][player_id]['team'] = team | |
tracks['players'][frame_num][player_id]['team_color'] = team_assigner.team_colors[team] | |
# Assign Ball Acquisition | |
player_assigner = PlayerBallAssigner() | |
team_ball_control = [] | |
for frame_num, player_track in enumerate(tracks['players']): | |
ball_bbox = tracks['ball'][frame_num][1]['bbox'] | |
assigned_player = player_assigner.assign_ball_to_player(player_track, ball_bbox) | |
if assigned_player != -1: | |
tracks['players'][frame_num][assigned_player]['has_ball'] = True | |
team_ball_control.append(tracks['players'][frame_num][assigned_player]['team']) | |
else: | |
if team_ball_control: # in case first few frames assigned_player == -1 | |
team_ball_control.append(team_ball_control[-1]) | |
team_ball_control = np.array(team_ball_control) | |
# Draw output | |
output_video_frames = tracker.draw_annotations(video_frames, tracks, team_ball_control) | |
output_video_frames = camera_movement_estimator.draw_camera_movement(output_video_frames, camera_movement_per_frame) | |
speed_and_distance_estimator.draw_speed_and_distance(output_video_frames, tracks) | |
# Save output video | |
output_path = 'output_videos/output_video.avi' | |
save_video(output_video_frames, output_path) | |
return output_path | |
# Gradio Interface | |
title="Football Match Analytics with YOLO and OpenCV" | |
description=""" | |
This demo processes football game videos to detect players and referees, track the ball, assign players to teams using color pixel clustering, and compute ball possession per team. | |
It also estimates camera movement with Lucas-Kanade optical flow and applies perspective transformation to calculate the real-time speed and total distance traveled by each player and the ball. | |
The YOLO detection model was fine-tuned with this dataset: https://universe.roboflow.com/roboflow-jvuqo/football-players-detection-3zvbc/dataset | |
Original Tutorial Reference: https://www.youtube.com/watch?v=neBZ6huolkg | |
**Note**: this space is running on a CPU, so inferencing new video may take some time. (Avg time during test: 1min processing per 5 second of video)""" | |
examples = [["input_videos/121364_0_small.mp4", True, True]] | |
interface = gr.Interface(fn=process_video, | |
inputs=[ | |
gr.Video(label="Upload Video (mp4, avi, mov) Max: 30sec"), | |
gr.Checkbox(label="Include Player Stats", value=True), | |
gr.Checkbox(label="Include Ball Stats", value=True) | |
], | |
outputs=gr.Video(label="Processed Video"), | |
examples=examples, | |
live=False, # No live update to avoid real-time processing issues | |
title=title, | |
description=description) # Allow users to download the processed video | |
interface.launch(debug=True, show_error = True) | |