Skip to content

Releases: fourMs/MGT-python

v1.5.0

Choose a tag to compare

@alexarje alexarje released this 27 Jun 15:56

Highlights

Changed

  • Motiongram/videogram output filenames now use direction-of-movement suffixes — _mgh/_vgh (horizontal) and _mgv/_vgv (vertical) — replacing the axis-based _mgy/_vgy and _mgx/_vgx. Applied to motion(), motiongrams(), videograms(), motion_mp(), and the ssm() intermediates. All show(key=...) keys — 'horizontal'/'vertical', the new mgh/mgv/vgh/vgv aliases, and the legacy mgx/mgy/vgx/vgy — still resolve correctly.

Added

  • silhouette_waterfall() and pose_waterfall() accept axes=False to render without any axes, ticks, labels, panes, or title (a clean 3D image).

See the CHANGELOG for full details.

v1.4.9

Choose a tag to compare

@alexarje alexarje released this 27 Jun 15:33

Highlights

Added

  • pose_waterfall(style=...) — new 'markers', 'skeleton', and 'both' styles (drawing the pose at n_samples time slices) alongside the default 'trajectories'.
  • pose(trajectory_background=...)'black' (default), 'white', or 'transparent' background for the trajectories image (legacy transparent_trajectories still honoured).
  • Orientation aliases for show(key=...): mgh/vgh (horizontal) and mgv/vgv (vertical).

Changed

  • overwrite now defaults to True for all functions — outputs are overwritten in place instead of auto-incrementing the filename. Pass overwrite=False for the old behaviour.
  • MgVideo.beat_statistics() now defaults to source='motion' (analyses the movement rhythm), so it differs from video.audio.beat_statistics(). Use source='audio' for the audio track.
  • pose() container handling: convert defaults to None ("auto") — MediaPipe reads the source directly (no intermediate AVI), OpenPose still converts for frame-accurate decoding. The result video is written in the original container (mp4 in → mp4 out; no avi→mp4 round-trip).
  • Decluttered pose images: removed titles from the trajectories and waterfall images and the average-pose image, and removed the average-pose colorbar. Trajectories omit marker-name labels by default (trajectory_labels=True to re-enable).

Fixed

  • The show(key=...) orientation keys for motiongrams/videograms were swapped'horizontal' now selects the horizontal-movement gram and 'vertical' the vertical one, with correct titles (in both MgVideo.show and MgList.show).

See the CHANGELOG for full details.

v1.4.8

Choose a tag to compare

@alexarje alexarje released this 27 Jun 12:18

Highlights

Added

  • pose_waterfall() — a 3D spatio-temporal waterfall where each marker's trajectory flows through (x, time, y) space, a pose-based counterpart to silhouette_waterfall().
  • pose(marker_history=N) — motion trails for each marker over the last N frames.
  • pose(trajectory_labels=True) — opt back into per-marker name labels on the trajectories image.

Changed

  • pose() now defaults to the MediaPipe backend (fast on plain CPU, 33 landmarks with depth + visibility, no CUDA-enabled OpenCV build needed). OpenPose (body_25/coco/mpi) remains available for multi-person scenes.
  • pose(overlay=False, background='white') now draws a black skeleton + markers (print-friendly inverted look).
  • The marker-trajectories image no longer shows name labels by default.
  • tempogram() gains a colorbar (matching the chromagram) and shows the estimated tempo rounded to one decimal with "BPM" in the title; the dotted tempo line was removed.
  • videograms()/motiongrams() display keys are now 'horizontal'/'vertical'.

Fixed

  • motionhistory(): normalize defaults to False and is guarded so it no longer over-brightens ("blows up") static clips.
  • Documentation refreshed across the docs site, wiki, and READMEs; the stale releases.md page now tracks the changelog.

See the CHANGELOG for full details.

v1.4.7

Choose a tag to compare

@alexarje alexarje released this 27 Jun 10:43

What's new in 1.4.7

Fixed

  • GPU detection_utils.py never imported cv2, so CUDA was always reported absent. GPU acceleration now works on a CUDA-enabled OpenCV: pose(device='gpu') (OpenPose), flow.dense(use_gpu=True), flow.sparse(use_gpu=True).
  • GPU sparse optical flow path corrected (point shapes + calc() returns).
  • MgList.show(key='mgx'/'vgx'/…) on motiongrams/videograms no longer crashes — selects the right panel.
  • Audio methods inherited by MgVideo (e.g. video.spectrogram()) no longer fail on a missing cache attribute.
  • CI on macOS/Windows: skip .ogg tests without libtheora; force the Matplotlib Agg backend.

Added

  • pose(use_cache=True) — re-render a different style/overlay/background from cached keypoints without re-running inference.
  • pose(data_format='c3d') — export markers to a C3D motion-capture file (optional c3d dependency).
  • tempogram(onset_strength=False) — single-panel tempogram matching the chromagram size.
  • beat_statistics(source='motion') on MgVideo — timing statistics from movement onsets.

Changed

  • Average-pose labels: numbers only (normalised QoM 0–1 | dominant frequency), stronger de-overlap.
  • motiontempo(): QoM normalised 0–1, renamed "Motion spectrum", with average QoM and beat-frequency lines + numbers.

v1.4.6

Choose a tag to compare

@alexarje alexarje released this 27 Jun 09:27

What's new in 1.4.6

Added

  • Space-time person visualisations: stroboscope() (chronophotography), silhouette_waterfall(), motionhistory() (Motion History Image), and spacetime_volume() (3D x,y,t silhouette point cloud). Silhouettes use MediaPipe selfie segmentation when available, falling back to background subtraction (method='auto'|'mediapipe'|'bgsub').
  • ssm(features='motiongrams', combine=True) — a single self-similarity matrix combining horizontal + vertical motion in one display.
  • pose() style now also applies to the average-pose image.

Changed

  • pose(): no-CUDA fallback uses the MediaPipe CPU (XNNPACK) delegate (reliable) instead of the fragile OpenGL-ES GPU delegate; new quiet=True suppresses MediaPipe's native C++/GL logs.

Fixed

  • Orientation: portrait/phone videos with a rotation flag are normalised at load (rotation baked into pixels, flag removed), so cv2-based processes no longer come out rotated 90°.

v1.4.5

Choose a tag to compare

@alexarje alexarje released this 26 Jun 21:15

What's new in 1.4.5

Added

  • Pose overhaulpose() now also exports an average-pose image (markers coloured/labelled by average quantity of motion in px/frame + dominant movement frequency in Hz, plus a per-marker stats CSV) and an all-trajectories image; labels are laid out to avoid overlap. New rendering controls: style (both/markers/skeleton), overlay (on video or plain background), background (black/white), and transparent_trajectories (transparent PNG for overlaying). MediaPipe backend is GPU-capable on the standard pip OpenCV.
  • convert=False on pose(), flow.dense()/flow.sparse(), directograms(), impacts(), motion_mp(), history_cv2() to skip AVI conversion and read mp4 directly.

Changed

  • Display via show() — analysis results (MgImage/MgFigure) no longer auto-render as a notebook cell's last expression; call .show(). HTML available via to_html(). info('frame') now returns an MgImage.
  • blur_faces() writes MP4/libx264 instead of MJPEG-AVI.

Performance

  • MgAudio caches decoded audio (multiple audio analyses decode the file once).
  • ffprobe() results cached per file (path+mtime+size) — metadata helpers share one subprocess call.

Fixed

  • All "invalid escape sequence" SyntaxWarnings on import.
  • Documented MgVideo.length = frame count vs MgAudio.length = seconds.
  • Removed 30 unused imports.

v1.4.4

Choose a tag to compare

@alexarje alexarje released this 26 Jun 10:53

What's new in 1.4.4

Added

  • MgVideo.eulerian() — Eulerian Video Magnification (Wu et al., SIGGRAPH 2012) to reveal subtle changes. mode='color' amplifies subtle colour changes (pulse/breathing); mode='motion' amplifies subtle motion. Reads/writes via the FFmpeg pipe (any format) and is memory-conscious (two-pass color / streaming-IIR motion), addressing the format & memory limits of existing PyEVM ports. Closes #212.
  • MgVideo.sonomotiongram() — sonifies the motiongram by treating it as a magnitude spectrogram and resynthesising audio via inverse STFT (Griffin–Lim). Returns an MgAudio. Closes #171.
  • MgVideo.motionvectors() — visualises the motion vectors carried by inter-frame codecs (MPEG/H.264/H.265) via FFmpeg's codecview. Closes #254.

Fixed

  • EVM/sonomotiongram timing: MgVideo.length is a frame count (not seconds), so audio duration is computed as length/fps and progress is tracked in frames.

v1.4.3

Choose a tag to compare

@alexarje alexarje released this 26 Jun 10:11

What's new in 1.4.3

Added

  • MgVideo.heatmap() — motion heatmap showing which parts of the video change the most (optionally overlaid on the average frame).
  • MgVideo.motiontempo() — estimates dominant movement tempo (Hz + BPM) from the quantity of motion (addresses #158).
  • descriptors(save_data=True) — save per-frame audio descriptors to csv/tsv/txt (closes #124).
  • MediaPipe GPU posepose() uses MediaPipe's GPU delegate; when device='gpu' is requested but OpenCV lacks CUDA, it auto-switches to the MediaPipe backend so the GPU is actually used.
  • cuda_build_available() / cuda_unavailable_reason() helpers.

Changed

  • Display model: MgImage/MgFigure no longer auto-render as a cell's last expression — display happens only via show(). This removes the duplicate (small + large) outputs from the audio figure methods and makes average() display only when show() is called. HTML helper kept as to_html().
  • GPU-fallback messages now explain the real cause (pip OpenCV is built without CUDA) rather than implying a missing GPU.

Fixed

  • spectrogram()/descriptors() time axis pinned to the actual data extent — no more trailing whitespace or mislabeled timeline when the container is longer than the decoded audio.

V1.4.2

Choose a tag to compare

@alexarje alexarje released this 26 Jun 09:29

Fixed

  • Critical: repaired a thresholdold corruption (from a botched threshthreshold
    replace) that broke the FFmpeg threshold filter, leaving motion(), motiongrams()
    and related functions producing no frames and crashing. Motion analysis works again.
  • skip with large values no longer crashes: atempo filters are chained for ratios
    above FFmpeg's per-filter limit of 100, and colons are stripped from output filenames.
  • Restored consistent behaviour of the threshold/filtertype options in motiongrams().

Added

  • info(type='summary') now reports video codec/profile, pixel format, color space,
    and audio codec/sample-rate/bit-rate alongside resolution, frames, fps, and duration.
  • audio.mfcc(), audio.tempo() (beat tracking with tempo, beat times, inter-beat
    intervals and beat regularity), and audio.beat_statistics() (circular timing analysis).
  • musicalgestures/_analysis.py: general signal/statistics utilities (smooth,
    bandpass, dominant_frequency, circular_stats, rayleigh_test, synchrony),
    exported at package level.

v1.4.0

Choose a tag to compare

@alexarje alexarje released this 26 Jun 08:26

Fixed

  • average() method restored — was accidentally removed in a prior refactor; now an alias for blend(component_mode='average')
  • average() silently accepts legacy kwargs method= and normalize= for backward compatibility
  • motiongrams() and motion() silently accept normalize= kwarg for backward compatibility
  • OGG video conversion, from_numpy() path bug, optical flow export, history weights parsing, cropping stall on Linux
  • All examples in docs/examples.md corrected to match current API

Added

  • MediaPipe pose estimation backend
  • GPU support (optional) for optical flow, face blurring, and pose estimation
  • Region-of-interest support for motion data
  • MgFeatures, MgVideoReader, MgPipeline, MgDataset, CLI (musicalgestures command)
  • Typed exceptions, enums, module-level logging

Changed

  • Minimum Python version raised to 3.10
  • threshold parameter name now consistent across all public APIs
  • contrast/brightness use integer range −100 to 100