Skip to content

Releases: tharindu326/physiotrack

v3.0.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 13:38
2dc81e3

3.0.0 (2026-09-25)

⚠ BREAKING CHANGES

  • face: Video(face_orientation=...) is replaced by
    Video(face_stages=[...]); FrameResult.face_orientation (list of dicts) is replaced
    by FrameResult.faces (a face Result); Detection.Face is removed in favour of
    pt.Face; detectors expose a public task attribute instead of _task;
    Models.Pose3D.FaceOrientation moved to Models.Face.Orientation;
    FaceOrientation.predict(source, bboxes) is now predict(source, faces), it no
    longer takes verbose/**kwargs, and its head-pose values change with the new
    crop; custom rppg_roi objects must accept skin_mask(frame, boxes=None).
  • pose: WholeBody keypoints 40-49 and 59-70 swap their left/right names
    (face_left_eyebrow_* <-> face_right_eyebrow_, face_left_eye_ <-> face_right_eye_*).

Features

  • face: face analysis as core face stages, face signals and Video support (b358381)

Bug Fixes

  • pose: name WholeBody face keypoints by the subject's side (642e522)
  • video: run every configured detector, keep the exact frame rate, accept Path sources (312fb1d)

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 26 Jul 18:11
7100beb

2.0.0 (2026-07-26)

⚠ BREAKING CHANGES

  • six public API changes, all from #11.
  • Pose3D.predict(json_path, vid_path, ...) no longer exists. It now takes
    keypoints in memory -- an array, a VideoResults, or frame records -- and
    returns a Pose3DResult instead of a (frames_data, poses) tuple. For the
    previous file-based workflow use Pose3D.predict_json(json_path, vid_path),
    which still returns the records alongside the result.
  • FaceOrientation.predict_batch(frames, bboxes_list) removed. Pass a list to
    predict() instead; it returns one result per frame, as every other predictor
    already did.
  • JointAnglePlotter.attach_panels() and .attach_canvas() removed. Use
    attach_to_frame(), which every other panel already used; the joint and ROM
    grids are now rendered as one canvas.
  • RealTimePlotter.plot() renamed to push(). It appends a sample, whereas
    plot() renders an existing result everywhere else in the library.
  • PoseCanonicalizer.transform_to_back_view(),
    .transform_to_left_side_view() and .transform_to_right_side_view() removed.
    Use to_canonical_geometric(poses, view=...) or canonicalize_pose(...).
  • Models.Pose3D.Canonicalizer.View removed. A canonical viewpoint is a
    parameter, not a checkpoint, so it is now the top-level CanonicalView enum.

Weight cache location also changed: checkpoints are no longer written inside the
installed package. Run physiotrack.migrate_weight_cache() once to move an
existing cache instead of re-downloading it.

Bug Fixes

  • correct DSP bugs, unify the predictor API, make the package installable (3d9c87d), closes #11 #11

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 19 Jul 11:21
08ba282

1.1.0 (2026-07-19)

Features

  • depth: add ZipDepth lightweight monocular depth backend (95c7d55)

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 16:09
8064f54

1.0.0 (2026-07-05)

⚠ BREAKING CHANGES

  • signals: physiotrack.signals.ppg.Filtering has been removed. Use the
    equivalent free functions in physiotrack.signals.filters (bandpass_filter,
    zero_mean_std_norm, bandpass_firwin, detrend_advanced).

Bug Fixes

  • signals: correct DSP bugs, unify filtering, add validated test suite (5ca0066)

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 04 Jul 18:25
37cc0de

0.5.0 (2026-07-04)

Features

  • contactless vitals — rPPG HR/HRV, respiration, configurable skin ROI (3ce1132)

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 04 Jul 13:57
99af483

0.4.0 (2026-07-04)

Features

  • high-quality supersampled overlay rendering (TrueType) across all panels (1697266)
  • joint-angle & clinical ROM overlay + depth/segmentation fixes (ad19a7d)
  • live rPPG heart rate from face-parsed skin + plotter-free signal APIs (45e2a5b)

v0.3.0

Choose a tag to compare

@tharindu326 tharindu326 released this 13 Jun 11:59

Physiotrack v0.3.0

This release adds face-part parsing to the segmentation subsystem and tidies the public API
so everything is reached through clean, hierarchical entry points.

✨ Added

  • Face parsing via Segmentation.Face (SegFace). Dense face-part segmentation into 19
    CelebAMask-HQ classes (skin, eyes, brows, nose, lips, hair, ears, glasses, hat, earring,
    necklace, neck, cloth, ...). It runs on face crops and, like Pose auto-detecting people,
    auto-detects faces with a YOLO face detector when no boxes are passed:
    from physiotrack import Segmentation
    result = Segmentation.Face().predict(image)   # auto-detects faces
    seg_map = result.seg_map                       # (H, W) face-part class map
    labels  = result.names                         # class id -> label
    overlay = result.plot()                        # 19-class palette overlay
    Registered as Models.Segmentation.SegFace.Face.swinb_celeba_512. Only the inference code is
    vendored (Swin-Base/CelebA model + transformer/utils), under the upstream MIT license.
  • New public exports so examples and user code never reach into internal module paths:
    • physiotrack: apply_3dpcnet_transform, reverse_3dpcnet_transform.
    • physiotrack.pose: COCO_WHOLEBODY_NAMES, HUMAN26M_NAMES.
    • physiotrack.signals: motion helpers (keypoint sequences, centroids, resampling, feature
      extraction) alongside the existing filters / normalization / rPPG / plotting exports.
  • Result.palette so palette-based segmentation maps (e.g. face parsing) overlay with the
    correct per-class colours.
  • examples/face_parsing.py — runnable SegFace example (auto-detect and explicit-box modes).
  • Demo video linked from the README.

♻️ Changed

  • Cleaner, hierarchical public API. README's "The Unified API" now includes a calling-hierarchy
    diagram showing the flat entry points, the model registry, the Result family, and the public
    subsystems (signals / pose / face).
  • Examples import only from public entry points. evaluate_pose.py and motion.py no longer
    reach into physiotrack.modules.* or deep file paths; they import from physiotrack,
    physiotrack.pose, and physiotrack.signals.
  • README architecture diagram, feature table, model registry, and project layout updated to
    include face parsing.

⚠️ Breaking

None.

🔁 Upgrading

No code changes required for existing usage. To use the new face parser:

from physiotrack import Segmentation
result = Segmentation.Face(device=0).predict(image)

📝 Notes

  • The SegFace checkpoint (segface_swinb_celeba_512.pt, slimmed to inference-only weights) is in
    the HuggingFace weights repo and must be pushed for the registry download to work.
  • All released canonicalizer/face-parsing checkpoints download on first use via the Models
    registry; no weights are bundled in the package.

Full documentation: see the README. License: GPL-3.0.

v0.2.0

Choose a tag to compare

@tharindu326 tharindu326 released this 13 Jun 10:24

Physiotrack v0.2.0

This release adds new pose-canonicalization models and substantially simplifies how 3DPCNet checkpoints are configured and loaded, alongside a full README overhaul.

✨ Added

  • Two new pose-canonicalization checkpoints, trained directly on TotalCapture with 48 augmented camera viewpoints (the earlier S2 / S3 models were trained on MMFi and evaluated cross-dataset on TotalCapture):
    • Models.Pose3D.Canonicalizer.Models._3DPCNetTC48_byCam — camera-disjoint split (test cams 41–48)
    • Models.Pose3D.Canonicalizer.Models._3DPCNetTC48_byAction — action-disjoint split (test action rom3)
    • These cut rotation error by roughly an order of magnitude (≈4.2° → 0.45°) and PA-MPJPE by ~10 mm versus the cross-dataset MMFi models. See the canonicalization comparison table in the README.
  • README: a detailed Mermaid architecture diagram of the whole library, a canonicalization model-comparison table, a table of contents, a project-layout map, and collapsible per-subsystem usage sections.

♻️ Changed

  • Single bundled inference config for all 3DPCNet models. Every canonicalizer checkpoint shares one network architecture, so inference now reads a single config shipped inside the package (physiotrack/modules/_3DCPNet/configs/inference_config.yaml). No per-model YAML is downloaded or required.
  • Model downloads are leaner. The canonicalizer now downloads only the .pth weights from Hugging Face; configuration is no longer fetched over the network. First-run setup is simpler and has one less failure mode.

⚠️ Removed / Breaking

  • Models.Pose3D.Canonicalizer.Configs enum removed. It only pointed at the per-model YAMLs that are no longer used. If you referenced it directly, drop the reference — the canonicalizer resolves its config automatically. Model selection (Models.Pose3D.Canonicalizer.Models.*) and views (...Canonicalizer.View.*) are unchanged.

🔁 Upgrading

No code changes are required for typical usage:

from physiotrack import canonicalize_pose, Models

canonical = canonicalize_pose(
    poses_3d,
    model=Models.Pose3D.Canonicalizer.Models._3DPCNetTC48_byCam,   # new, recommended
    view="front",
)

If you were passing a downloaded per-model config path manually, you can stop — omit config_path and the bundled config is used. The GEOMETRIC (training-free) path is unaffected.

📝 Notes

  • The four canonicalizer checkpoints on Hugging Face follow the best_model_3DPCNet*.pth naming convention; per-model .yaml files have been retired.
  • All architecture/inference code is unchanged for existing models — the new TC48 checkpoints use the same network as the S2 / S3 HybridGCNTransformer models and load with the existing code.

Full documentation: see the README. License: GPL-3.0.

v0.1.0

Choose a tag to compare

@tharindu326 tharindu326 released this 13 Jun 09:48

The first public release of Physiotrack, an open-source Python toolkit for contactless human understanding — turning RGB / RGB-D / thermal video into interpretable physiological and behavioral signals. Developed at the Center for Machine Vision and Signal Processing (CMVS), University of Oulu.

Philosophy: send meaning, not pixels — extract human-state features so downstream systems can reason about states instead of raw video.

⚠️ This is an early 0.x release. The library is under active development and the public API may change before 1.0.

✨ Highlights

  • One unified API across every image predictor: configure the model, call .predict(img) (or model(img)), read a structured Result, and draw with result.plot().
  • Composable subsystems that work standalone or as an end-to-end pipeline via the Video orchestrator.
  • Automatic model management — weights resolve through the Models registry and download on first use (Ultralytics + Hugging Face).

📦 What's included

Subsystem Capability Backends
Detection Multi-person / object boxes YOLO11, RT-DETR, VR-specific
Tracking Persistent IDs, occlusion-robust OC-SORT, ByteTrack, StrongSORT, BoostTrack
Pose 2D 17 (COCO) or 133 (whole-body) keypoints ViTPose, Sapiens, YOLO11-Pose
Pose 3D Lift 2D keypoints to 3D over time MotionBERT, DDHPose
Canonicalization Viewpoint-invariant 3D pose alignment 3DPCNet, geometric
Segmentation Pixel-level instance masks YOLO-Seg, Sapiens, VR-Head
Depth Monocular dense depth Depth-Anything-V2 (s/b/l)
Face Detection + 3D head orientation YOLO-Face, 6DRepNet360, CMVS-FO-VR
Signals rPPG (HR/RR) + motion features POS, CHROM, LGI, OMIT + filters
Views Bird's-eye floor map, ego-video & depth overlays —

Inputs: monocular RGB, RGB-D + infrared (Azure Kinect), depth, and thermal video; live cameras, files, or single images.

🚀 Installation

git clone https://github.com/tharindu326/physiotrack.git
cd physiotrack
pip install -e .

Install the PyTorch build matching your platform/CUDA first (requirements.txt pins a CUDA 12.8 build, torch==2.9.1). Model weights are not bundled and download automatically on first use.

🧑‍💻 Quick start

import cv2
import physiotrack as pt

frame = cv2.imread("frame.png")

det    = pt.Detection.Person(conf=0.25, device=0)
result = det.predict(frame)
cv2.imwrite("out.png", result.plot())

pose   = pt.Pose.Person()
people = pose.predict(frame)
wrist  = people[0].keypoints.by_name("left_wrist")
print(wrist.x, wrist.y, wrist.confidence)

End-to-end video pipeline:

from physiotrack import Video, Detection, Pose, Tracker, TrackerConfig, Models

Video(
    source="input.mp4",
    detector=Detection.Person(),
    pose=Pose.Custom(model=Models.Pose.ViTPose.WholeBody.b_wholebody),
    tracker=Tracker(config=TrackerConfig(tracker="ocsort", classes=[0])),
    output_dir="output",
).run(output_video="out.mp4", output_json="out.json")

⚠️ Known limitations

  • API is pre-1.0 and subject to change.
  • A CUDA GPU is recommended for real-time use; CPU works but is slower.
  • Model weights are downloaded on demand and are not part of the package.
  • Some subsystems (e.g. parts of signals) are still evolving.

📚 Citation

If you use Physiotrack in your research, please cite the relevant papers listed in the README.

🙏 Acknowledgments

Supported by the University of Oulu and the Research Council of Finland through the 6G Flagship Programme (346208), Profi5 HiDyn (326291), and Profi7 Hybrid Intelligence (352788). Computational resources provided by CSC (IT Center for Science, Finland).


Full documentation: see the README. License: GPL-3.0.