#!/usr/bin/env python3 import json import os import tempfile import time from pathlib import Path from ultralytics import YOLO IMAGE_PATH = Path("/dev/shm/robot_frame.jpg") OUTPUT_PATH = Path("/dev/shm/r1_detections.json") MODEL = "yolo26n.pt" CONFIDENCE = 0.35 IMAGE_SIZE = 640 def atomic_write_json(path: Path, data): with tempfile.NamedTemporaryFile( mode="w", dir=path.parent, delete=False, suffix=".tmp", ) as f: json.dump( data, f, ensure_ascii=False, indent=2, ) tmp = f.name os.replace(tmp, path) def main(): print(f"[YOLO] Loading {MODEL}") model = YOLO(MODEL) print("[YOLO] Ready") print(f"[YOLO] Camera: {IMAGE_PATH}") print(f"[YOLO] Output: {OUTPUT_PATH}") last_mtime = None while True: try: if not IMAGE_PATH.exists(): time.sleep(0.05) continue mtime = IMAGE_PATH.stat().st_mtime_ns if mtime == last_mtime: time.sleep(0.01) continue last_mtime = mtime results = model.predict( source=str(IMAGE_PATH), conf=CONFIDENCE, imgsz=IMAGE_SIZE, verbose=False, ) if not results: continue result = results[0] height, width = result.orig_shape detections = [] if result.boxes is not None: for box in result.boxes: class_id = int(box.cls[0]) confidence = float(box.conf[0]) x1, y1, x2, y2 = [ float(v) for v in box.xyxy[0] ] cx = (x1 + x2) / 2.0 cy = (y1 + y2) / 2.0 detections.append({ "class_id": class_id, "class": result.names[class_id], "confidence": confidence, "box": { "x1": x1, "y1": y1, "x2": x2, "y2": y2, }, "center": { "x": cx, "y": cy, }, "normalized_center": { "x": cx / width, "y": cy / height, }, }) data = { "timestamp": time.time(), "width": width, "height": height, "detections": detections, } atomic_write_json( OUTPUT_PATH, data, ) objects = ", ".join( f"{d['class']} {d['confidence']:.2f}" for d in detections ) if objects: print(f"[YOLO] {objects}") else: print("[YOLO] no objects") except KeyboardInterrupt: print("\n[YOLO] stopped") break except Exception as e: print(f"[YOLO] error: {e}") time.sleep(0.25) if __name__ == "__main__": main()