Spaces:
Sleeping
Sleeping
import gradio as gr | |
from inference_sdk import InferenceHTTPClient | |
from PIL import Image, ImageDraw, ImageFont | |
import os | |
from collections import defaultdict | |
API_KEY = os.getenv("ROBOFLOW_API_KEY") | |
CLIENT = InferenceHTTPClient( | |
api_url="https://detect.roboflow.com", | |
api_key=API_KEY | |
) | |
# Model settings | |
MODEL_ID = "hvacsym/5" | |
CONFIDENCE_THRESHOLD = 0.3 # Confidence threshold for filtering predictions | |
GRID_SIZE = (3, 3) # 4x4 segmentation | |
def process_image(image_path): | |
"""Processes an uploaded image and returns the final image with bounding boxes & symbol counts.""" | |
original_image = Image.open(image_path) | |
width, height = original_image.size | |
seg_w, seg_h = width // GRID_SIZE[1], height // GRID_SIZE[0] | |
# Create a copy of the image for bounding boxes | |
final_image = original_image.copy() | |
draw_final = ImageDraw.Draw(final_image) | |
# Load font | |
try: | |
font = ImageFont.truetype("arial.ttf", 10) | |
except: | |
font = ImageFont.load_default() | |
# Dictionary for total counts | |
total_counts = defaultdict(int) | |
# Process each segment | |
for row in range(GRID_SIZE[0]): | |
for col in range(GRID_SIZE[1]): | |
x1, y1 = col * seg_w, row * seg_h | |
x2, y2 = (col + 1) * seg_w, (row + 1) * seg_h | |
segment = original_image.crop((x1, y1, x2, y2)) | |
segment_path = f"segment_{row}_{col}.png" | |
segment.save(segment_path) | |
# Run inference | |
result = CLIENT.infer(segment_path, model_id=MODEL_ID) | |
filtered_predictions = [ | |
pred for pred in result["predictions"] if pred["confidence"] * 100 >= CONFIDENCE_THRESHOLD | |
] | |
# Draw bounding boxes and update counts | |
for obj in filtered_predictions: | |
sx, sy, sw, sh = obj["x"], obj["y"], obj["width"], obj["height"] | |
class_name = obj["class"] | |
confidence = obj["confidence"] | |
total_counts[class_name] += 1 | |
# Adjust coordinates for final image | |
x_min, y_min = x1 + (sx - sw // 2), y1 + (sy - sh // 2) | |
x_max, y_max = x1 + (sx + sw // 2), y1 + (sy + sh // 2) | |
# Draw bounding box | |
draw_final.rectangle([x_min, y_min, x_max, y_max], outline="green", width=2) | |
# Draw label | |
text = f"{class_name} {confidence:.2f}" | |
draw_final.text((x_min + 2, y_min - 10), text, fill="white", font=font) | |
# Save final image with bounding boxes | |
final_image_path = "final_detected_image.png" | |
final_image.save(final_image_path) | |
return final_image_path, total_counts | |
def process_uploaded_image(image): | |
"""Gradio wrapper function that calls `process_image` and formats the output.""" | |
final_image_path, total_counts = process_image(image) | |
# Convert count dictionary to readable text | |
count_text = "\n".join([f"{label}: {count}" for label, count in total_counts.items()]) | |
return final_image_path, count_text | |
# Deploy with Gradio | |
iface = gr.Interface( | |
fn=process_uploaded_image, | |
inputs=gr.Image(type="filepath"), # Gradio input expects a file path | |
outputs=[gr.Image(type="filepath"), gr.Text()], | |
title="HVAC Symbol Detector", | |
description="Upload an HVAC blueprint image. The model will detect symbols and return the final image with bounding boxes along with symbol counts." | |
) | |
# Launch the Gradio app | |
iface.launch() | |