feat(unraid): add Tail 2 GPU pose service
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import math
|
||||
import queue
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def finite01(value: float) -> float:
|
||||
value = float(value)
|
||||
return min(1.0, max(0.0, value)) if math.isfinite(value) else 0.0
|
||||
|
||||
|
||||
def normalize_bbox(bbox: list[float] | np.ndarray, width: int, height: int) -> list[float]:
|
||||
return [finite01(bbox[0] / width), finite01(bbox[1] / height),
|
||||
finite01(bbox[2] / width), finite01(bbox[3] / height)]
|
||||
|
||||
|
||||
def normalize_keypoints(points: np.ndarray, width: int, height: int, count: int) -> list[list[float]]:
|
||||
out = [[finite01(p[0] / width), finite01(p[1] / height), finite01(p[2])] for p in points[:count]]
|
||||
out.extend([[0.0, 0.0, 0.0] for _ in range(count - len(out))])
|
||||
return out
|
||||
|
||||
|
||||
def inverse_letterbox(points: np.ndarray, scale: float, pad_x: float, pad_y: float) -> np.ndarray:
|
||||
out = points.copy().astype(float)
|
||||
out[..., 0] = (out[..., 0] - pad_x) / scale
|
||||
out[..., 1] = (out[..., 1] - pad_y) / scale
|
||||
return out
|
||||
|
||||
|
||||
class LatestQueue:
|
||||
def __init__(self) -> None:
|
||||
self._q: queue.Queue[Any] = queue.Queue(maxsize=1)
|
||||
|
||||
def put(self, item: Any) -> None:
|
||||
try:
|
||||
self._q.put_nowait(item)
|
||||
except queue.Full:
|
||||
try:
|
||||
self._q.get_nowait()
|
||||
except queue.Empty:
|
||||
pass
|
||||
self._q.put_nowait(item)
|
||||
|
||||
def get(self, timeout: float | None = None) -> Any:
|
||||
return self._q.get(timeout=timeout)
|
||||
|
||||
def qsize(self) -> int:
|
||||
return self._q.qsize()
|
||||
|
||||
|
||||
class BroadcastHub:
|
||||
def __init__(self) -> None:
|
||||
self._clients: set[asyncio.Queue] = set()
|
||||
self._lock = threading.Lock()
|
||||
|
||||
def add(self) -> asyncio.Queue:
|
||||
q: asyncio.Queue = asyncio.Queue(maxsize=1)
|
||||
with self._lock:
|
||||
self._clients.add(q)
|
||||
return q
|
||||
|
||||
def remove(self, q: asyncio.Queue) -> None:
|
||||
with self._lock:
|
||||
self._clients.discard(q)
|
||||
|
||||
def publish_on_loop(self, loop: asyncio.AbstractEventLoop, message: dict) -> None:
|
||||
def publish() -> None:
|
||||
with self._lock:
|
||||
clients = list(self._clients)
|
||||
for q in clients:
|
||||
if q.full():
|
||||
try:
|
||||
q.get_nowait()
|
||||
except asyncio.QueueEmpty:
|
||||
pass
|
||||
q.put_nowait(message)
|
||||
loop.call_soon_threadsafe(publish)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Frame:
|
||||
pixels: np.ndarray
|
||||
received_ns: int
|
||||
decode_ms: float
|
||||
|
||||
Reference in New Issue
Block a user