Skip to content
BetaThis project is currently in its beta version.Updates might take a while to roll out.There's still plenty of work left to do.Thanks for your patience while we keep building.
BetaThis project is currently in its beta version.Updates might take a while to roll out.There's still plenty of work left to do.Thanks for your patience while we keep building.
mHumanTrackAImHumanTrackAI

Architecture

mHumanTrackAI is built as two processes, designed to be independently testable:

  • Python engine (engine/) — owns cameras, ML inference, occlusion prediction, multi-camera fusion, gesture evaluation, and recording. Knows nothing about Win32/WPF.
  • C# / WPF app (app/) — UI, visualization, OS-level input drivers, and process lifecycle. Knows nothing about ML.

C# / WPF App

mHumanTrackAI.App.exe

  • EngineHost — spawns the Python engine in a Win32 Job Object
  • EngineService — NetMQ client; marshals packets to the UI
  • InputRouter → SendInput (accessibility cursor + clicks)
  • GamingRouter → ViGEm Xbox 360 (gaming controller)
  • HotkeyService → Ctrl+Alt+P global panic
  • ForegroundWatcher → per-app profile / mode auto-switch
ZeroMQ · loopback 127.0.0.1

data

PUB → SUB

:5555 · landmarks JSON

control

REQ ↔ REP

:5556 · command JSON

preview

PUB → SUB

:5557 · meta JSON + JPEG

Python Engine

python -m engine.main

  • camera.capture — OpenCV MultiCamera (threaded grab)
  • tracking — RTMSource (RTMW) / MediaPipeSource / DummySource
  • fusion.fuse — per-joint best-view selector + src tag
  • predictor.process — One-Euro + Kalman + IK occlusion predict
  • gestures — GestureEngine / GamingEngine → input / controller
  • server.publish_landmarks() + publish_preview()

Two-process design

The C# app owns the lifecycle of the Python engine. EngineHost spawns the engine as a hidden child process inside a Win32 Job Object (KILL_ON_JOB_CLOSE), which guarantees the Python child dies with the app even on a hard crash. If an engine is already listening on the control port (for example, a developer started one manually), EngineHost attaches to it instead of spawning a new one.

The engine runs a main publish loop on the main thread and a control loop on a daemon thread, so commands never block the tracking pipeline.

IPC channels

The two processes communicate over ZeroMQ (NetMQ on C#, pyzmq on Python) across TCP loopback. The wire format is newline-less JSON, schema version 1, defined in shared/schema/ipc.schema.json.

ChannelPatternPortPayload
dataPUB → SUB5555landmarks JSON
controlREQ ↔ REP5556command JSON
previewPUB → SUB5557meta JSON + JPEG

The control channel handles commands such as ping, getConfig, setConfig, setMode, setCamera, captureTPose, startRecording, exportRecording, playRecording, listCameras, and shutdown.

Key design decisions

  • The engine binds all three sockets; the app connects. This makes the engine the single source of truth for port state.
  • Preview is rate-decoupled (small high-water mark; stale frames dropped) so JPEG encoding never adds latency to the landmark stream.
  • Job Object lifecycle ensures the Python child cannot outlive the app.
  • Config hot-reloadsetConfig / setCamera / loadProfile set a dirty flag; the next loop iteration reopens the camera/source with new settings.

DTOs are currently hand-written on both sides and kept in sync manually against the schema. Schema codegen is noted as a reasonable future upgrade.