from edge.config import Config from edge.tracking import IouTracker from edge.smoothing import TrackSmootherPool from edge.detectors.fall import FallDetector from edge.detectors.immobility import ImmobilityWatchdog from edge.detectors.ghost import GhostIncidentDetector from edge.detectors.zone import ZoneIntrusionDetector from edge.engine import EventEngine from edge.snapshot import RingBuffer, FaceBlurrer, Snapshotter from edge.models import BBox def _head_boxes(persons: list) -> list: # Head region for face anonymization (PIPA). Sized from the PERSON bbox, not a fixed # ~40x40 patch — a close worker fills far more than 40px, so a constant box left the face # fully identifiable. Centered on the nose when it is confident, else on the bbox's top # (the head is the upper part of the person) so a bad keypoint can't move the blur off it. boxes = [] for p in persons: bb = p.bbox nose = p.keypoints[0] half_w = max(8.0, 0.25 * bb.width) if nose.conf >= 0.3: cx, cy = nose.x, nose.y else: cx, cy = bb.cx, bb.y1 + 0.12 * bb.height boxes.append(BBox(cx - half_w, cy - 0.18 * bb.height, cx + half_w, cy + 0.08 * bb.height)) return boxes def run_once(source, pose, tracker, pool, engine, ring, snapshotter, sink, now_fn): ok, frame = source.read() if not ok: return [] now = now_fn() persons = pose.infer(frame) tracks = tracker.update(persons, now) # RAW keypoints; smoothing happens per-track below lost = tracker.lost() for tr in tracks: f = tr.latest f.keypoints = pool.smoother_for(tr.track_id).smooth(f.keypoints, now) ring.push(now, frame) h, w = frame.shape[:2] events = engine.process(tracks, lost, now, frame_wh=(w, h)) for tr in lost: pool.forget(tr.track_id) if events: snaps = snapshotter.capture([frame], [_head_boxes(persons)]) for e in events: sink.try_send(e, snaps) return events def build_pipeline(config: Config, source, pose) -> dict: return { "source": source, "pose": pose, "tracker": IouTracker(), "pool": TrackSmootherPool(), "engine": EventEngine( FallDetector(config.fall), ImmobilityWatchdog(config.immobility), GhostIncidentDetector(config.ghost), ZoneIntrusionDetector([], config.zone), config.engine, ), "ring": RingBuffer(), "snapshotter": Snapshotter(FaceBlurrer()), }