Spaces:
Sleeping
Sleeping
File size: 8,634 Bytes
ccf69b0 f51d821 bfd7e4a ccf69b0 f2b1904 ccf69b0 f2b1904 f51d821 ccf69b0 bfd7e4a ccf69b0 f2b1904 bfd7e4a ccf69b0 bfd7e4a f2b1904 bfd7e4a ccf69b0 bfd7e4a ccf69b0 bfd7e4a ccf69b0 bfd7e4a f2b1904 ccf69b0 f2b1904 ccf69b0 bfd7e4a ccf69b0 bfd7e4a f2b1904 bfd7e4a ccf69b0 f2b1904 ccf69b0 f2b1904 ccf69b0 f2b1904 bfd7e4a ccf69b0 bfd7e4a ccf69b0 f2b1904 ccf69b0 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 bfd7e4a f2b1904 ccf69b0 f2b1904 ccf69b0 f2b1904 ccf69b0 f2b1904 ccf69b0 f2b1904 ccf69b0 bfd7e4a ccf69b0 bfd7e4a ccf69b0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# app.py
import gradio as gr
from ultralytics import YOLO
from PIL import Image, ImageDraw, ImageFont
from huggingface_hub import hf_hub_download
import torch
import os
import requests # Keep for potential future use, though hf_hub_download handles model download
# --- Configuration ---
MODEL_REPO_ID = "biglam/historic-newspaper-illustrations-yolov11"
# Choose 'yolo11n.pt' (nano) or 'yolo11s.pt' (small)
MODEL_FILENAME = "yolo11n.pt" # Defaulting to the smaller nano model
# --- Model Loading ---
model = None # Initialize model variable
# Use try-except block for robust model loading
try:
# Step 1: Download the specific model weights file from Hugging Face Hub
print(f"Downloading model weights '{MODEL_FILENAME}' from '{MODEL_REPO_ID}'...")
model_path = hf_hub_download(repo_id=MODEL_REPO_ID, filename=MODEL_FILENAME)
print(f"Model weights downloaded to: {model_path}")
# Step 2: Load the YOLO model using the downloaded weights file path
model = YOLO(model_path)
print(f"Ultralytics YOLO model loaded successfully from '{model_path}'.")
# You can check the device it's running on (YOLO usually auto-detects)
device = next(model.parameters()).device
print(f"Model is running on device: {device}")
except Exception as e:
print(f"Error loading Ultralytics YOLO model: {e}")
# Ensure model remains None if loading fails
# --- Image Processing Function ---
def detect_illustrations(input_image: Image.Image) -> Image.Image:
"""
Detects illustrations in the input image using the loaded Ultralytics YOLO model
and draws bounding boxes around them.
Args:
input_image (PIL.Image.Image): The image uploaded by the user.
Returns:
PIL.Image.Image: The image with bounding boxes drawn around detected illustrations,
or the original image if the model failed to load or no objects are detected.
"""
if model is None:
print("Model not loaded. Returning original image.")
if input_image is None:
# Handle case where user clicks submit without uploading image
# Create a placeholder image or return None based on Gradio handling
placeholder = Image.new('RGB', (300, 100), color = 'white')
d = ImageDraw.Draw(placeholder)
try:
font = ImageFont.truetype("arial.ttf", 15)
except IOError:
font = ImageFont.load_default()
d.text((10,10), "Error: Model not loaded & No image provided.", fill="red", font=font)
return placeholder
# If image exists but model failed, add error text to image
draw = ImageDraw.Draw(input_image)
try:
font = ImageFont.truetype("arial.ttf", 20) # Adjust font/size as needed
except IOError:
font = ImageFont.load_default()
draw.text((10, 10), "Error: Model could not be loaded.", fill="red", font=font)
return input_image
if input_image is None:
# Handle case where user clicks submit without uploading image after model is loaded
placeholder = Image.new('RGB', (300, 100), color = 'white')
d = ImageDraw.Draw(placeholder)
try:
font = ImageFont.truetype("arial.ttf", 15)
except IOError:
font = ImageFont.load_default()
d.text((10,10), "Please upload an image.", fill="orange", font=font)
return placeholder
# Convert image to RGB if it's not already
if input_image.mode != "RGB":
input_image = input_image.convert("RGB")
# Perform object detection using the Ultralytics model
try:
# results is a list of Results objects
# Set confidence threshold if desired, e.g., model(input_image, conf=0.5)
results = model(input_image, verbose=False) # Set verbose=True for more detailed logs
print(f"Detection results obtained.") # Log results for debugging
except Exception as e:
print(f"Error during inference: {e}")
# Handle inference errors
output_image = input_image.copy()
draw = ImageDraw.Draw(output_image)
try:
font = ImageFont.truetype("arial.ttf", 20)
except IOError:
font = ImageFont.load_default()
draw.text((10, 10), f"Error during detection: {e}", fill="red", font=font)
return output_image
# --- Draw Bounding Boxes ---
output_image = input_image.copy()
draw = ImageDraw.Draw(output_image)
# Define colors
label_colors = {"illustration": "red"}
default_color = "blue"
# Load a font for labels
try:
# Using a slightly larger font
font = ImageFont.truetype("arial.ttf", 18)
except IOError:
print("Arial font not found. Using Pillow's default font.")
font = ImageFont.load_default()
# Process results (Ultralytics returns results per image, here we have one)
if results and results[0].boxes:
boxes = results[0].boxes # Access the Boxes object
print(f"Found {len(boxes)} potential objects.")
for box in boxes:
# Extract coordinates (xyxy format)
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) # Get coordinates as integers
# Get confidence score and class ID
conf = box.conf[0].item() # Confidence score
cls = int(box.cls[0].item()) # Class ID
# Get the label name from the model's names dictionary
class_name = model.names[cls] if cls in model.names else f"Class_{cls}"
print(f"Detected '{class_name}' (ID: {cls}) with confidence {conf:.2f} at [{x1}, {y1}, {x2}, {y2}]")
# Choose color based on label
color = label_colors.get(class_name, default_color)
# Draw the bounding box
draw.rectangle([(x1, y1), (x2, y2)], outline=color, width=3)
# Prepare label text
label_text = f"{class_name}: {conf:.2f}"
# Calculate text size and position using textbbox
try:
text_bbox = draw.textbbox((0, 0), label_text, font=font) # Use (0,0) for size calc
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
except AttributeError: # Fallback for older Pillow versions
text_width, text_height = font.getsize(label_text)
# Draw background rectangle for text for better visibility
text_bg_y = y1 - text_height - 4 # Position above box
if text_bg_y < 0: text_bg_y = y1 + 2 # Adjust if too close to top edge
draw.rectangle(
[(x1, text_bg_y), (x1 + text_width + 4, text_bg_y + text_height + 2)],
fill=color
)
# Draw the label text
draw.text((x1 + 2, text_bg_y + 1), label_text, fill="white", font=font)
else:
print("No objects detected in the results.")
# Optionally add text indicating no detections
draw.text((10, 10), "No illustrations detected.", fill="orange", font=font)
return output_image
# --- Gradio Interface ---
# Define the input and output components
image_input = gr.Image(type="pil", label="Upload Newspaper Image")
image_output = gr.Image(type="pil", label="Detected Illustrations")
# Define title and description for the Gradio app
title = f"Historic Newspaper Illustration Detector ({MODEL_FILENAME})"
description = f"""
Upload an image of a historic newspaper page.
This app uses the `{MODEL_REPO_ID}` model ('{MODEL_FILENAME}' weights via Ultralytics YOLO)
to detect illustrations and draw bounding boxes around them.
Processing might take a moment depending on the image size and server load.
Model loading happens once when the Space starts.
"""
article = f"<p style='text-align: center'><a href='https://huggingface.co/{MODEL_REPO_ID}' target='_blank'>Model Card</a> | Powered by <a href='https://github.com/ultralytics/ultralytics' target='_blank'>Ultralytics YOLO</a></p>"
# Create the Gradio interface
iface = gr.Interface(
fn=detect_illustrations,
inputs=image_input,
outputs=image_output,
title=title,
description=description,
article=article,
examples=[
# Add relative paths if you include example images in your Space repo
# e.g., ["example1.jpg"]
],
allow_flagging='never'
)
# --- Launch the App ---
if __name__ == "__main__":
# Launch the app. share=True creates a public link (useful for testing locally)
# In Hugging Face Spaces, share=True is not needed.
iface.launch()
|