Spaces:
Sleeping
Sleeping
| """Object detection via YOLOv8, with a graceful no-ML fallback. | |
| When the optional ML stack (torch + ultralytics) is available and enabled, this | |
| detects furniture-like objects so their floor footprints can be treated as | |
| blocked space. Otherwise it returns an empty list and the floor is treated as | |
| unobstructed — the rest of the pipeline still runs. | |
| Grounding DINO is intentionally OUT for the MVP (YOLO covers detection). | |
| """ | |
| from __future__ import annotations | |
| import functools | |
| from dataclasses import dataclass, field | |
| from pathlib import Path | |
| from ..config import settings | |
| from .ml_runtime import ml_available | |
| # COCO labels that occupy floor space and matter for placement. | |
| FURNITURE_LABELS = { | |
| "bed", "couch", "chair", "dining table", "tv", "potted plant", | |
| "refrigerator", "toilet", "sink", "bench", "vase", "book", "clock", | |
| } | |
| class Detection: | |
| label: str | |
| confidence: float | |
| box: list[float] = field(default_factory=list) # [x1, y1, x2, y2] in pixels | |
| def _load_model(): | |
| from ultralytics import YOLO | |
| return YOLO(settings.YOLO_MODEL) | |
| def detect_objects(image_path: Path, conf_threshold: float = 0.30) -> list[Detection]: | |
| """Detect objects in an image. Returns [] when ML is unavailable/failing.""" | |
| if not ml_available(): | |
| return [] | |
| try: | |
| model = _load_model() | |
| result = model(str(image_path), verbose=False)[0] | |
| names = result.names | |
| out: list[Detection] = [] | |
| for b in result.boxes: | |
| conf = float(b.conf) | |
| if conf < conf_threshold: | |
| continue | |
| label = str(names[int(b.cls)]) | |
| xyxy = [float(v) for v in b.xyxy[0].tolist()] | |
| out.append(Detection(label=label, confidence=conf, box=xyxy)) | |
| return out | |
| except Exception: | |
| # Missing weights / runtime error -> degrade gracefully. | |
| return [] | |