CoolFace
Apppublic

aishaikds/soccernet_object_tracking

sourceHugging Faceupdated 11mo agoView on Hugging Face
1likes
app.py389 linesDownload Raw Back to root
1import gradio as gr2from PIL import Image, ImageDraw, ImageFont3import cv24import numpy as np5import pandas as pd6import tempfile7import sys8import os9from huggingface_hub import hf_hub_download10 11print("="*60)12print("Setting up RF-DETR SoccerNet Model...")13print("="*60)14 15repo_id = "julianzu9612/RFDETR-Soccernet"16 17try:18    # Download inference.py19    print("\nDownloading inference.py...")20    inference_path = hf_hub_download(repo_id=repo_id, filename="inference.py")21    22    # Read the file23    with open(inference_path, 'r') as f:24        inference_code = f.read()25    26    print("\n๐Ÿ”ง Patching inference.py...")27    print("   Changing: RFDETRBase() โ†’ RFDETRLarge()")28    29    # THE FIX: Replace RFDETRBase with RFDETRLarge30    inference_code = inference_code.replace(31        'from rfdetr import RFDETRBase',32        'from rfdetr import RFDETRLarge'33    )34    inference_code = inference_code.replace(35        'self.model = RFDETRBase()',36        'self.model = RFDETRLarge()'37    )38    39    # Save the patched version40    with open(inference_path, 'w') as f:41        f.write(inference_code)42    print("โœ“ Patched inference.py successfully!")43    44    # Download weights45    print("\nDownloading model weights...")46    weights_path = hf_hub_download(repo_id=repo_id, filename="weights/checkpoint_best_regular.pth")47    print(f"โœ“ Downloaded weights")48    49    # Setup environment50    cache_dir = os.path.dirname(inference_path)51    52    if cache_dir not in sys.path:53        sys.path.insert(0, cache_dir)54    55    original_dir = os.getcwd()56    os.chdir(cache_dir)57    58    # Create weights directory structure59    weights_dir = os.path.join(cache_dir, "weights")60    os.makedirs(weights_dir, exist_ok=True)61    62    expected_weights = os.path.join(weights_dir, "checkpoint_best_regular.pth")63    if not os.path.exists(expected_weights):64        import shutil65        shutil.copy(weights_path, expected_weights)66        print(f"โœ“ Weights copied to: {expected_weights}")67    68    print("\n" + "="*60)69    print("Initializing RF-DETR SoccerNet Model...")70    print("="*60)71    72    # Import and initialize the patched model73    from inference import RFDETRSoccerNet74    75    detector = RFDETRSoccerNet()76    print("\nโœ… Model loaded successfully!")77    78    os.chdir(original_dir)79    80except Exception as e:81    print(f"\nโŒ Error: {e}")82    import traceback83    traceback.print_exc()84    raise85 86# Helper functions for Gradio87def draw_detections_on_image(image, df):88    """Draw bounding boxes on PIL image"""89    draw = ImageDraw.Draw(image)90    91    try:92        font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16)93    except:94        font = ImageFont.load_default()95    96    colors = {97        'ball': (255, 0, 0),98        'player': (0, 255, 0),99        'referee': (255, 255, 0),100        'goalkeeper': (0, 0, 255)101    }102    103    for _, row in df.iterrows():104        x1, y1, x2, y2 = row['x1'], row['y1'], row['x2'], row['y2']105        class_name = row['class_name']106        conf = row['confidence']107        color = colors.get(class_name, (255, 255, 255))108        109        draw.rectangle([x1, y1, x2, y2], outline=color, width=3)110        111        text = f"{class_name}: {conf:.2f}"112        bbox = draw.textbbox((x1, y1-20), text, font=font)113        draw.rectangle([bbox[0]-2, bbox[1]-2, bbox[2]+2, bbox[3]+2], fill=color)114        draw.text((x1, y1-20), text, fill=(0, 0, 0), font=font)115    116    return image117 118def process_image_interface(image, confidence_threshold):119    """Process image with the model"""120    if image is None:121        return None, pd.DataFrame()122    123    try:124        # Save temporary image125        temp_path = tempfile.mktemp(suffix='.jpg')126        Image.fromarray(image if isinstance(image, np.ndarray) else np.array(image)).save(temp_path)127        128        # Process with model129        df = detector.process_image(temp_path, confidence_threshold=confidence_threshold)130        131        # Draw detections132        img = Image.open(temp_path)133        annotated_img = draw_detections_on_image(img, df)134        135        # Cleanup136        os.remove(temp_path)137        138        return annotated_img, df139        140    except Exception as e:141        print(f"Error processing image: {e}")142        import traceback143        traceback.print_exc()144        return None, pd.DataFrame()145 146def process_video_interface(video, confidence_threshold, frame_skip, max_frames):147    """Process video with the model"""148    if video is None:149        return None, pd.DataFrame()150    151    try:152        max_frames_val = int(max_frames) if max_frames > 0 else None153        154        # Process video155        print(f"Processing video with confidence={confidence_threshold}, frame_skip={frame_skip}, max_frames={max_frames_val}")156        df = detector.process_video(157            video,158            confidence_threshold=confidence_threshold,159            frame_skip=int(frame_skip),160            max_frames=max_frames_val161        )162        163        # Create annotated video164        cap = cv2.VideoCapture(video)165        fps = int(cap.get(cv2.CAP_PROP_FPS))166        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))167        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))168        169        output_path = tempfile.mktemp(suffix='.mp4')170        fourcc = cv2.VideoWriter_fourcc(*'mp4v')171        out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))172        173        frame_num = 0174        while cap.isOpened():175            ret, frame = cap.read()176            if not ret:177                break178            179            # Get detections for this frame180            frame_detections = df[df['frame'] == frame_num]181            182            if not frame_detections.empty:183                rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)184                pil_img = Image.fromarray(rgb_frame)185                annotated_pil = draw_detections_on_image(pil_img, frame_detections)186                frame = cv2.cvtColor(np.array(annotated_pil), cv2.COLOR_RGB2BGR)187            188            out.write(frame)189            frame_num += 1190        191        cap.release()192        out.release()193        194        return output_path, df195        196    except Exception as e:197        print(f"Error processing video: {e}")198        import traceback199        traceback.print_exc()200        return None, pd.DataFrame()201 202# Create Gradio interface203with gr.Blocks(title="โšฝ Soccer Object Detection", theme=gr.themes.Soft()) as demo:204    gr.Markdown("""205    # โšฝ Soccer Object Detection with RF-DETR206    207    Professional-grade object detection for soccer videos using RF-DETR-Large model.208    209    ### Model: [julianzu9612/RFDETR-Soccernet](https://huggingface.co/julianzu9612/RFDETR-Soccernet)210    - **Architecture**: RF-DETR-Large (128M parameters)211    - **Performance**: 85.7% mAP@50, 49.8% mAP212    - **Dataset**: SoccerNet-Tracking 2023 (42,750 images)213    - **Classes**: Ball, Player, Referee, Goalkeeper214    """)215    216    with gr.Tab("๐Ÿ“ธ Image Detection"):217        gr.Markdown("### Upload a soccer image to detect objects")218        219        with gr.Row():220            with gr.Column():221                image_input = gr.Image(label="Upload Soccer Image", type="numpy")222                image_confidence = gr.Slider(223                    minimum=0.1, 224                    maximum=1.0, 225                    value=0.5, 226                    step=0.05, 227                    label="Confidence Threshold",228                    info="Lower values detect more objects but may include false positives"229                )230                image_button = gr.Button("๐Ÿ” Detect Objects", variant="primary", size="lg")231            232            with gr.Column():233                image_output = gr.Image(label="Detected Objects")234        235        image_detections = gr.Dataframe(236            label="Detection Results",237            wrap=True,238            interactive=False239        )240        241        image_button.click(242            fn=process_image_interface,243            inputs=[image_input, image_confidence],244            outputs=[image_output, image_detections]245        )246        247        gr.Examples(248            examples=[],249            inputs=image_input,250            label="Example Images (Upload your own!)"251        )252    253    with gr.Tab("๐ŸŽฅ Video Detection"):254        gr.Markdown("### Upload a soccer video to track objects frame by frame")255        256        with gr.Row():257            with gr.Column():258                video_input = gr.Video(label="Upload Soccer Video")259                video_confidence = gr.Slider(260                    minimum=0.1,261                    maximum=1.0,262                    value=0.5,263                    step=0.05,264                    label="Confidence Threshold"265                )266                video_frame_skip = gr.Slider(267                    minimum=1,268                    maximum=10,269                    value=5,270                    step=1,271                    label="Frame Skip",272                    info="Process every Nth frame (higher = faster but less detections)"273                )274                video_max_frames = gr.Number(275                    value=300,276                    label="Max Frames to Process",277                    info="Set to 0 to process entire video (300 frames โ‰ˆ 10 seconds at 30 FPS)"278                )279                280                gr.Markdown("""281                #### โšก Performance Tips:282                - **CPU**: 2-3 FPS (slow) - Use frame_skip=5 and limit frames283                - **GPU**: 12-30 FPS (fast) - Can process full videos284                - **Quick test**: Use 300 frames with frame_skip=5285                """)286                287                video_button = gr.Button("๐ŸŽฌ Process Video", variant="primary", size="lg")288            289            with gr.Column():290                video_output = gr.Video(label="Annotated Video")291        292        video_detections = gr.Dataframe(293            label="Detection Results",294            wrap=True,295            interactive=False296        )297        298        video_button.click(299            fn=process_video_interface,300            inputs=[video_input, video_confidence, video_frame_skip, video_max_frames],301            outputs=[video_output, video_detections]302        )303    304    with gr.Tab("โ„น๏ธ About"):305        gr.Markdown("""306        ## About This Model307        308        ### ๐ŸŽฏ Detected Classes309        310        | Class | Color | Precision | Description |311        |-------|-------|-----------|-------------|312        | ๐Ÿ”ด Ball | Red | 78.5% | Soccer ball detection |313        | ๐ŸŸข Player | Green | 91.3% | Field players from both teams |314        | ๐ŸŸก Referee | Yellow | 85.2% | Match officials |315        | ๐Ÿ”ต Goalkeeper | Blue | 88.9% | Specialized goalkeeper detection |316        317        ### ๐Ÿ“Š Model Performance318        319        - **mAP@50**: 85.7%320        - **mAP**: 49.8%321        - **mAP@75**: 52.0%322        - **Parameters**: 128M323        - **Training Time**: ~14 hours on NVIDIA A100 40GB324        325        ### ๐ŸŽ“ Training Details326        327        - **Dataset**: SoccerNet-Tracking 2023328        - **Images**: 42,750 annotated images329        - **Source**: Professional soccer broadcasts330        - **Input Resolution**: 1280x1280 pixels331        - **Optimizer**: AdamW (lr=1e-4)332        333        ### ๐Ÿ’ก Best Practices334        335        1. **Confidence Threshold**: 336           - Use 0.5 for general detection337           - Use 0.7+ for high-precision applications338        339        2. **Video Quality**:340           - Works best on 720p+ broadcast footage341           - Standard broadcast camera angles preferred342        343        3. **Frame Processing**:344           - frame_skip=1: Every frame (best accuracy, slow)345           - frame_skip=5: Every 5th frame (good balance)346           - frame_skip=10: Every 10th frame (fast, lower accuracy)347        348        ### ๐Ÿšจ Limitations349        350        - Optimized for professional broadcast footage351        - May have reduced accuracy in poor lighting352        - Small balls may be missed when heavily occluded353        - Camera angle dependency354        355        ### ๐Ÿ“š Use Cases356        357        - **Sports Analytics**: Player tracking, formation analysis358        - **Broadcast Enhancement**: Automatic highlighting, statistics overlay359        - **Research**: Tactical analysis, computer vision benchmarking360        - **Video Analytics**: Automated video processing pipelines361        362        ### ๐Ÿ”— Links363        364        - [Model on Hugging Face](https://huggingface.co/julianzu9612/RFDETR-Soccernet)365        - [SoccerNet Dataset](https://www.soccer-net.org/)366        - [RF-DETR Paper](https://arxiv.org/abs/2304.08069)367        368        ### ๐Ÿ“„ Citation369        370        ```bibtex371        @misc{rfdetr-soccernet-2025,372          title={RF-DETR SoccerNet: High-Performance Soccer Object Detection},373          author={Computer Vision Research Team},374          year={2025},375          publisher={Hugging Face},376          url={https://huggingface.co/julianzu9612/rf-detr-soccernet}377        }378        ```379        380        ---381        382        **License**: Apache 2.0383        """)384 385print("\n" + "="*60)386print("๐Ÿš€ Launching Gradio Interface...")387print("="*60)388 389demo.launch()