Spaces:
Sleeping
Sleeping
import gradio as gr | |
from ultralytics import YOLO | |
from PIL import Image | |
import cv2 | |
import numpy as np | |
import tempfile | |
import os | |
from pathlib import Path | |
# Load the YOLOv8 model | |
model = YOLO('yolov8n.pt') | |
def process_image(image): | |
""" | |
Process a single image for object detection | |
""" | |
results = model(image) | |
# Get detection information | |
boxes = results[0].boxes | |
detection_info = [] | |
for box in boxes: | |
class_id = int(box.cls[0]) | |
class_name = results[0].names[class_id] | |
confidence = float(box.conf[0]) | |
detection_info.append(f"{class_name}: {confidence:.2%}") | |
return Image.fromarray(results[0].plot()), "\n".join(detection_info) | |
def process_video(video_path): | |
""" | |
Process video for object detection | |
""" | |
with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as temp_file: | |
output_path = temp_file.name | |
cap = cv2.VideoCapture(video_path) | |
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | |
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |
fps = int(cap.get(cv2.CAP_PROP_FPS)) | |
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) | |
detection_summary = [] | |
frame_count = 0 | |
try: | |
while cap.isOpened(): | |
ret, frame = cap.read() | |
if not ret: | |
break | |
frame_count += 1 | |
results = model(frame) | |
# Collect detection information for this frame | |
if frame_count % int(fps) == 0: # Sample every second | |
for box in results[0].boxes: | |
class_id = int(box.cls[0]) | |
class_name = results[0].names[class_id] | |
detection_summary.append(class_name) | |
annotated_frame = results[0].plot() | |
out.write(annotated_frame) | |
finally: | |
cap.release() | |
out.release() | |
# Create summary of detected objects | |
if detection_summary: | |
from collections import Counter | |
counts = Counter(detection_summary) | |
summary = "\n".join([f"{obj}: {count} occurrences" for obj, count in counts.most_common()]) | |
else: | |
summary = "No objects detected" | |
return output_path, summary | |
def detect_objects(media): | |
""" | |
Unified function to handle both image and video inputs | |
""" | |
if media is None: | |
return None, None, None, "Please upload an image or video to begin detection.", gr.update(visible=True), gr.update(visible=False) | |
try: | |
if isinstance(media, str) and media.lower().endswith(('.mp4', '.avi', '.mov')): | |
output_video, detection_summary = process_video(media) | |
return (None, output_video, detection_summary, | |
"β Video processing complete! Check the detection summary below.", | |
gr.update(visible=False), gr.update(visible=True)) | |
else: | |
if isinstance(media, str): | |
image = cv2.imread(media) | |
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
else: | |
image = media | |
processed_image, detection_info = process_image(image) | |
return (processed_image, None, detection_info, | |
"β Image processing complete! Check the detections below.", | |
gr.update(visible=True), gr.update(visible=False)) | |
except Exception as e: | |
return None, None, None, f"β Error: {str(e)}", gr.update(visible=False), gr.update(visible=False) | |
# Custom CSS for styling | |
custom_css = """ | |
#app-container { | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
} | |
#logo-img { | |
max-height: 100px; | |
margin-bottom: 20px; | |
} | |
.upload-box { | |
border: 2px dashed #ccc; | |
padding: 20px; | |
text-align: center; | |
border-radius: 8px; | |
background-color: #f8f9fa; | |
margin: 20px 0; | |
} | |
.results-container { | |
background-color: #ffffff; | |
border-radius: 8px; | |
padding: 15px; | |
box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
margin-top: 20px; | |
} | |
.detection-info { | |
background-color: #f8f9fa; | |
padding: 15px; | |
border-radius: 8px; | |
margin-top: 10px; | |
font-family: monospace; | |
} | |
.center { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
margin-bottom: 1rem; | |
} | |
""" | |
# Create Gradio interface | |
with gr.Blocks(css=custom_css) as demo: | |
with gr.Column(elem_id="app-container"): | |
# Logo and Header | |
with gr.Column(elem_classes="center"): | |
gr.Image("logo-h.png", | |
show_label=False, | |
container=False, | |
elem_id="logo-img", | |
height=100) | |
gr.Markdown("# π Object Detection") | |
# Upload Section | |
with gr.Column(elem_classes="upload-box"): | |
gr.Markdown("### π€ Upload your file") | |
input_media = gr.File( | |
label="Drag and drop or click to upload (Images: jpg, jpeg, png | Videos: mp4, avi, mov)", | |
file_types=["image", "video"] | |
) | |
# Status Message | |
status_text = gr.Textbox( | |
label="Status", | |
value="Waiting for upload...", | |
interactive=False | |
) | |
# Detection Information | |
detection_info = gr.Textbox( | |
label="Detection Results", | |
elem_classes="detection-info", | |
interactive=False | |
) | |
# Results Section | |
with gr.Column(elem_classes="results-container"): | |
with gr.Row(): | |
with gr.Column(visible=False) as image_column: | |
output_image = gr.Image(label="Detected Objects") | |
with gr.Column(visible=False) as video_column: | |
output_video = gr.Video(label="Processed Video") | |
# Handle file upload | |
input_media.upload( | |
fn=detect_objects, | |
inputs=[input_media], | |
outputs=[ | |
output_image, | |
output_video, | |
detection_info, | |
status_text, | |
image_column, | |
video_column | |
] | |
) | |
if __name__ == "__main__": | |
demo.launch(share=True) |