import cv2 import numpy as np import time import threading from collections import deque import torch from config import * from helpers import clip_box, crop_roi, preprocess_for_yolo, filter_yolo_boxes_with_scores # Async YOLO worker # ========================= class YOLOWorker: def __init__(self, model): self.model = model self.req = deque(maxlen=YOLO_QUEUE_MAX) self.res = deque(maxlen=1) self.lock = threading.Lock() self.running = False self.thread = threading.Thread(target=self._loop, daemon=True) def start(self): self.running = True self.thread.start() def stop(self): self.running = False self.thread.join(timeout=1.0) def submit(self, frame_eff_bgr, roi_box_eff, mode, ts): with self.lock: self.req.append((frame_eff_bgr, roi_box_eff, mode, ts)) def try_get(self): with self.lock: if not self.res: return None return self.res.pop() def _loop(self): while self.running: item = None with self.lock: if self.req: item = self.req.pop() self.req.clear() if item is None: time.sleep(0.001) continue frame, roi_box, mode, ts = item h, w = frame.shape[:2] frame_infer = preprocess_for_yolo(frame) dets = [] infer_ms = 0.0 used_roi = False try: if roi_box is not None: roi_box = clip_box(roi_box, w, h) crop, ox, oy = crop_roi(frame_infer, roi_box) if crop.size > 0: used_roi = True t0 = time.perf_counter() with torch.inference_mode(): r = self.model( crop, conf=YOLO_CONF_EFFECTIVE, imgsz=IMG_SIZE_ROI, verbose=False, max_det=MAX_DET, device=DEVICE, half=USE_HALF )[0] infer_ms = (time.perf_counter() - t0) * 1000.0 dets = filter_yolo_boxes_with_scores( r, frame_w=w, frame_h=h, offset_x=ox, offset_y=oy, min_conf=BT_LOW ) else: sh, sw = frame_infer.shape[:2] short = min(sh, sw) scale = 1.0 target = IMG_SIZE_FULL if short > target: scale = target / float(short) small = cv2.resize( frame_infer, (int(sw * scale), int(sh * scale)), interpolation=cv2.INTER_AREA ) else: small = frame_infer t0 = time.perf_counter() with torch.inference_mode(): r = self.model( small, conf=YOLO_CONF_EFFECTIVE, imgsz=IMG_SIZE_FULL, verbose=False, max_det=MAX_DET, device=DEVICE, half=USE_HALF )[0] infer_ms = (time.perf_counter() - t0) * 1000.0 dets_s = filter_yolo_boxes_with_scores( r, frame_w=small.shape[1], frame_h=small.shape[0], offset_x=0, offset_y=0, min_conf=BT_LOW ) if scale != 1.0: inv = 1.0 / scale dets = [ np.array([d[0] * inv, d[1] * inv, d[2] * inv, d[3] * inv, d[4]], dtype=np.float32) for d in dets_s ] else: dets = dets_s except Exception: dets = [] infer_ms = 0.0 with self.lock: self.res.append((dets, ts, mode, infer_ms, used_roi)) # =========================