Yolo_detect / app.py
KPrashanth's picture
Upload app.py
146b696 verified
import cv2
import numpy as np
import gradio as gr
from ultralytics import YOLO
# -------------------------
# Load model once (global)
# -------------------------
MODEL_NAME = "yolov8n.pt"
model = YOLO(MODEL_NAME)
CLASS_OF_INTEREST = "person"
def is_in_danger_zone(box, zone):
"""
box: (x1, y1, x2, y2)
zone: ((zx1, zy1), (zx2, zy2))
overlap logic: any partial overlap triggers True
"""
x1, y1, x2, y2 = box
(zx1, zy1), (zx2, zy2) = zone
overlap_x = (x1 < zx2) and (x2 > zx1)
overlap_y = (y1 < zy2) and (y2 > zy1)
return overlap_x and overlap_y
def process_frame(frame, zx1, zy1, zx2, zy2, conf_thres):
"""
frame: numpy array (H, W, 3) from Gradio webcam (RGB)
returns: annotated frame (RGB), status markdown
"""
if frame is None:
return None, "Waiting for webcam input…"
# Gradio gives RGB; OpenCV drawing expects BGR
bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
h, w = bgr.shape[:2]
# Clamp and fix zone coordinates
zx1 = int(np.clip(zx1, 0, w - 1))
zx2 = int(np.clip(zx2, 0, w - 1))
zy1 = int(np.clip(zy1, 0, h - 1))
zy2 = int(np.clip(zy2, 0, h - 1))
if zx2 < zx1:
zx1, zx2 = zx2, zx1
if zy2 < zy1:
zy1, zy2 = zy2, zy1
danger_zone = ((zx1, zy1), (zx2, zy2))
# Draw danger zone
cv2.rectangle(bgr, danger_zone[0], danger_zone[1], (0, 0, 255), 2)
# Run YOLO (on original RGB frame or BGR — ultralytics handles numpy arrays)
results = model.predict(source=frame, conf=float(conf_thres), verbose=False)
alert_triggered = False
persons_in_zone = 0
persons_total = 0
for r in results:
names = r.names
if r.boxes is None:
continue
boxes_xyxy = r.boxes.xyxy.cpu().numpy() if hasattr(r.boxes.xyxy, "cpu") else np.array(r.boxes.xyxy)
cls_ids = r.boxes.cls.cpu().numpy() if hasattr(r.boxes.cls, "cpu") else np.array(r.boxes.cls)
confs = r.boxes.conf.cpu().numpy() if hasattr(r.boxes.conf, "cpu") else np.array(r.boxes.conf)
for (x1, y1, x2, y2), cls_id, cf in zip(boxes_xyxy, cls_ids, confs):
class_name = names[int(cls_id)]
if class_name != CLASS_OF_INTEREST:
continue
persons_total += 1
x1, y1, x2, y2 = map(int, [x1, y1, x2, y2])
# Draw person bbox
cv2.rectangle(bgr, (x1, y1), (x2, y2), (255, 0, 0), 2)
label = f"{class_name}: {float(cf):.2f}"
cv2.putText(bgr, label, (x1, max(20, y1 - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2)
# Zone overlap check
if is_in_danger_zone((x1, y1, x2, y2), danger_zone):
alert_triggered = True
persons_in_zone += 1
if alert_triggered:
cv2.putText(
bgr,
f"ALERT! {persons_in_zone} person(s) in danger zone",
(20, 40),
cv2.FONT_HERSHEY_SIMPLEX,
1.0,
(0, 0, 255),
3
)
status = f"## 🔴 ALERT\n**{persons_in_zone}** person(s) inside danger zone.\n\nTotal persons detected: **{persons_total}**"
else:
status = f"## ✅ SAFE\nNo person inside danger zone.\n\nTotal persons detected: **{persons_total}**"
# Convert back to RGB for Gradio output
out_rgb = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
return out_rgb, status
with gr.Blocks(title="YOLOv8 Danger Zone (Webcam)") as demo:
gr.Markdown(
"# YOLOv8 Danger Zone Detection (Webcam)\n"
"Use your webcam, define a rectangular danger zone, and detect if any **person** enters it.\n\n"
"**Note:** On Hugging Face Spaces, server-side audio (pygame) isn’t reliable. We show a clear on-screen alert instead."
)
with gr.Row():
with gr.Column():
cam = gr.Image(
label="Webcam Input",
sources=["webcam"],
type="numpy"
)
with gr.Column():
out = gr.Image(label="Annotated Output", type="numpy")
status_md = gr.Markdown("Waiting for webcam input…")
with gr.Accordion("Danger Zone Controls", open=True):
with gr.Row():
zx1 = gr.Slider(0, 1280, value=100, step=1, label="Zone X1 (left)")
zy1 = gr.Slider(0, 720, value=100, step=1, label="Zone Y1 (top)")
with gr.Row():
zx2 = gr.Slider(0, 1280, value=400, step=1, label="Zone X2 (right)")
zy2 = gr.Slider(0, 720, value=400, step=1, label="Zone Y2 (bottom)")
conf = gr.Slider(0.1, 0.9, value=0.35, step=0.05, label="Confidence Threshold")
# Stream webcam frames to backend (Gradio 5 streaming)
cam.stream(
fn=process_frame,
inputs=[cam, zx1, zy1, zx2, zy2, conf],
outputs=[out, status_md],
stream_every=0.1 # approx 10 fps snapshots (depends on device/network)
)
demo.queue().launch()