import gradio as gr import cv2 import numpy as np import torch from ultralytics import YOLO import time from typing import Tuple, Dict, List, Optional, Union # Initialize default confidence threshold DEFAULT_CONF_THRESHOLD = 0.25 # Load YOLO model (using YOLOv8 as it's optimized for CPU) model = YOLO('yolov8n.pt') # using the nano version for faster CPU inference # Set to CPU explicitly model.to('cpu') def detect_objects(image, conf_threshold: float = DEFAULT_CONF_THRESHOLD): if image is None: return None, "No image provided" # Convert image from RGB (Gradio) to BGR (OpenCV) image_cv = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # Start timer for FPS calculation start_time = time.time() # Run inference with user-defined confidence threshold results = model(image_cv, conf=conf_threshold) # Calculate FPS fps = 1.0 / (time.time() - start_time) # Process results if len(results) == 0: return image, "No detections found" result = results[0] output_image = image.copy() # Get detections boxes = result.boxes.cpu().numpy() detection_count = {} # Draw bounding boxes and labels for box in boxes: x1, y1, x2, y2 = map(int, box.xyxy[0]) conf = float(box.conf[0]) cls_id = int(box.cls[0]) cls_name = result.names[cls_id] # Update detection count detection_count[cls_name] = detection_count.get(cls_name, 0) + 1 # Generate a color based on class ID (for consistent colors per class) color = (int(hash(cls_name) % 256), int(hash(cls_name + "salt") % 256), int(hash(cls_name + "pepper") % 256)) # Draw bounding box cv2.rectangle(output_image, (x1, y1), (x2, y2), color, 2) # Draw label background text = f"{cls_name}: {conf:.2f}" text_size, _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1) cv2.rectangle(output_image, (x1, y1 - text_size[1] - 5), (x1 + text_size[0], y1), color, -1) # Draw text cv2.putText(output_image, text, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) # Create detection summary summary = f"FPS: {fps:.1f}\n" if detection_count: summary += "Detected objects:\n" for cls_name, count in sorted(detection_count.items()): summary += f"- {cls_name}: {count}\n" else: summary += "No objects detected" return output_image, summary def process_webcam(image, conf_threshold: float = DEFAULT_CONF_THRESHOLD): """Process webcam frames for real-time detection""" return detect_objects(image, conf_threshold) def process_uploaded_image(image, conf_threshold: float = DEFAULT_CONF_THRESHOLD): """Process uploaded image for detection""" return detect_objects(image, conf_threshold) # Create custom HTML header for the app custom_css = """ """ custom_header = f""" {custom_css}