object-detector / image-processing /object-detector.py
AsyncCoder-10's picture
Upload image-processing/object-detector.py
2231656 verified
Raw History Blame Contribute Delete
5.71 kB
import torch
from transformers import AutoImageProcessor, AutoModelForObjectDetection
from PIL import ImageDraw, ImageFont
import gradio as gr
# ---------------------------
# 1. Load model + processor once
# ---------------------------
# Loading outside the function means we download and initialize
# the model only at startup, not on every prediction.
MODEL_NAME = "facebook/detr-resnet-50"
# Processor: resizes/normalizes the image and converts detection outputs
# back into real pixel coordinates for the original image size.
processor = AutoImageProcessor.from_pretrained(MODEL_NAME)
# Model: DETR (DEtection TRansformer) - detects objects and draws boxes
# around them, along with a predicted label and confidence score.
model = AutoModelForObjectDetection.from_pretrained(MODEL_NAME)
model.eval() # inference mode - disables dropout etc.
# Automatically use GPU if available, otherwise fall back to CPU.
device = "cuda" if torch.cuda.is_available() else "cpu"
model.to(device)
# A small color palette to cycle through so each box gets a different color.
COLORS = [
"#e6194b",
"#3cb44b",
"#ffe119",
"#4363d8",
"#f58231",
"#911eb4",
"#46f0f0",
"#f032e6",
"#bcf60c",
"#fabebe",
]
# ---------------------------
# 2. Define the detection logic
# ---------------------------
def detect_objects(image, confidence_threshold: float = 0.7):
"""
Run object detection on the uploaded image and draw bounding boxes
around every object detected above the given confidence threshold.
Args:
image: A PIL image uploaded by the user.
confidence_threshold: Minimum confidence score (0-1) required
to keep a detected object.
Returns:
annotated: The image with bounding boxes drawn on it.
summary: A text list of detected objects and their confidence scores.
"""
# Guard against no image being uploaded.
if image is None:
return None, "Please upload an image."
# Convert the PIL image into the tensor format DETR expects,
# and move it to the same device (CPU/GPU) as the model.
inputs = processor(images=image, return_tensors="pt").to(device)
# Run the model without tracking gradients (faster, less memory - we're not training).
with torch.no_grad():
outputs = model(**inputs)
# DETR predicts boxes in a normalized format; this converts them
# back to actual pixel coordinates based on the original image size.
# image.size is (width, height), but target_sizes expects (height, width).
target_sizes = torch.tensor([image.size[::-1]])
# Keep only detections whose confidence is above the threshold.
results = processor.post_process_object_detection(
outputs, target_sizes=target_sizes, threshold=confidence_threshold
)[0]
# Make a copy of the image so we can draw on it without changing the original.
annotated = image.convert("RGB").copy()
draw = ImageDraw.Draw(annotated)
detections = []
# results["scores"], ["labels"], and ["boxes"] are aligned lists -
# each index i refers to the same detected object.
for i, (score, label_id, box) in enumerate(
zip(results["scores"], results["labels"], results["boxes"])
):
# box is [x_min, y_min, x_max, y_max] in pixel coordinates.
box = [round(coord, 1) for coord in box.tolist()]
# Convert the numeric label ID (e.g. 17) into a readable name (e.g. "cat").
label = model.config.id2label[label_id.item()]
confidence = round(score.item(), 3)
# Cycle through the color palette so each box looks distinct.
color = COLORS[i % len(COLORS)]
# Draw the bounding box rectangle and a text label above it.
draw.rectangle(box, outline=color, width=3)
draw.text((box[0], max(box[1] - 12, 0)), f"{label} ({confidence})", fill=color)
detections.append(f"{label}: {confidence}")
# Build a readable summary string, or a fallback message if nothing was found.
summary = (
"\n".join(detections)
if detections
else "No objects detected above the confidence threshold."
)
return annotated, summary
# ---------------------------
# 3. Build the web UI with Gradio
# ---------------------------
with gr.Blocks(title="Object Detector") as demo:
gr.Markdown("## Object Detector")
gr.Markdown("Powered by Hugging Face DETR (facebook/detr-resnet-50)")
with gr.Row():
# Left side: where the user uploads their image.
image_input = gr.Image(type="pil", label="Upload Image")
# Right side: the same image, but with boxes drawn on it.
image_output = gr.Image(type="pil", label="Detected Objects")
# Lets the user control how strict detection should be.
# Lower threshold = more (possibly less accurate) detections.
confidence_slider = gr.Slider(
minimum=0.1, maximum=0.95, value=0.7, step=0.05, label="Confidence Threshold"
)
detect_btn = gr.Button("Detect Objects")
detections_output = gr.Textbox(label="Detections", lines=6)
# Wire the button click to the detect_objects function:
# takes the image + slider value as input, and updates
# both the annotated image and the text summary.
detect_btn.click(
fn=detect_objects,
inputs=[image_input, confidence_slider],
outputs=[image_output, detections_output],
)
# ---------------------------
# 4. Start the web server
# ---------------------------
if __name__ == "__main__":
demo.launch()