Releases: fourMs/MGT-python
Release list
1.11.2
Documentation and citation metadata only; no change to any code path.
CITATION.cffstates the software's authors, its version and its DOI, and the README carries a DOI badge, so the record Zenodo archives is built from the repository rather than by hand.musicalgestures.examples, the one public definition without a docstring, is described.- The documentation says where this package stops and its three sibling toolboxes start.
Note on the archive. This is the first release since the Zenodo GitHub integration was switched on. The integration cannot see a deposition it did not create, so this release begins a new concept DOI, and the hand-made lineage 10.5281/zenodo.21949007 is frozen at 1.11.1. The repository is repointed at the new lineage immediately after this release.
MGT-python 1.11.1
Changed
- The threshold figure recorded in 1.11.0 is superseded by the full corpus. That release
quoted a 0.4 % median cost atthreshold=0.05, measured on 83 clips. The run finished at 345:
the cost is 0.2 %, the direction is still consistent and significant at the lower
thresholds (202 of 345 at the default, sign test p = 0.002), and atthreshold=0.2it stops
being significant at all (187 of 345, p = 0.13). The conclusion is unchanged and stronger --- the
picture-legible default is free, for practical purposes, for machine analysis of this material.
The sequence is recorded in the docstring because it is the useful part: 6 clips said no effect,
23 said 1.2 %, 83 said 0.4 %, 345 says 0.2 %.
MGT-python 1.11.0
Fixed
-
pose()on OpenCV 5 fails with a message instead of anAttributeError. OpenCV removed its
Caffe importer in 5.0:cv2.dnn.readNetFromCaffeno longer exists andcv2.dnn.readNetrefuses
the format rather than falling back. The OpenPose backends here — BODY_25, COCO and MPI — are
Caffe models, so on such a build they cannot run at all. The failure used to surface as
AttributeError: module 'cv2.dnn' has no attribute 'readNetFromCaffe'from deep inside the run,
and only after offering to download 200 MB of weights that the environment could never load.The check now happens before the weights are looked for, and names both ways out:
pose(model= 'mediapipe')withpip install musicalgestures[pose], orpip install 'opencv-python<5'to
keep the OpenPose skeletons. It is deliberately not an automatic switch to MediaPipe — its 33
landmarks are a different skeleton from BODY_25's 25, so a silent substitution would return data
that looks like what was asked for and is not. -
The MediaPipe fallback no longer falls back into a wall. With MediaPipe missing,
pose()
announced a fallback to BODY_25 and then failed on it, because that fallback assumed OpenCV could
always load a Caffe model. Where it cannot, there is nowhere to fall back to, and the error now
says so and names the one install that would work. -
Test_pose_gpuskips where OpenPose cannot run. Its two cases had been failing with the bare
AttributeErrorabove on any OpenCV 5 machine, which is what made the incompatibility read as a
fault in the pose code rather than in the environment. They test device selection on the OpenPose
path, so where that path does not exist there is nothing to select and the tests skip with the
reason stated.
Documentation
- What the visualisation threshold costs a measurement is now measured, not
just flagged._motionvideo's header said there was "no reason to think
the value that looks best is the value that measures best". On 83 clips of a
corpus of everyday sound-producing actions, scored by how far the action
stands above the lead-in it interrupts: no threshold improves the
separation, more clips lose contrast than gain it at every step (55 of 83 at
threshold=0.05, sign test p = 0.004), and the median cost at the default is
0.4 % against a per-clip spread of 0.39 to 2.66. The default is very nearly
free for machine analysis of this material. Two cautions are recorded with
it: one criterion was scored, and smaller samples of the same code gave 1.2 %
at 23 clips and no effect at 6. - Also recorded: a threshold moves any landmark computed from the same series,
so a statistic measured across that landmark shows a much larger apparent
effect than the signal loss --- 23 % against 9 % here.
MediaPipe is unaffected by any of this and remains the default backend; it carries its own weights
and never touches cv2.dnn. Verified end to end on OpenCV 5.0.0 with MediaPipe 1.0.0: 163 frames
of 33 landmarks off a real clip, a person found in 44 % of them.
MGT-python 1.10.0
Added
normalize=False on mg_motion, for machine analysis. The exported quantity of motion has always been divided by each clip's own maximum, so every clip peaks at exactly 1.0. That is what a plot on a 0–1 axis wants — the same expression appears in the plotting code — and it is invisible in the numbers themselves, which is why it surprises people. It makes quantity of motion incomparable between clips: a small gesture and a violent one both reach 1.0, and one bright frame sets the scale for everything around it.
normalize=False exports the untouched sum of pixel values instead. The column is renamed to QomRaw rather than merely rescaled, so a file cannot be misread later: a Qom column is always per-clip normalised and a QomRaw column never is. normalize was already in mg_motion's signature and had never been used.
Fixed
TSV export wrote quantity of motion as 0 or 1. The writer formatted the column with %d while the value had already been divided by its maximum, so np.savetxt truncated every fraction to an integer. Normalised values now write as floats; QomRaw writes as an integer, which is what it is. This changes the content of TSV exports, which have not been relied on.
Changed
_motionvideo states what its defaults are for. They are tuned to produce a legible picture, not a measurement — the right choice for motion videos, motiongrams and plots, and worth saying now that the same functions are used to produce numbers. Three are visualisation choices: threshold=0.05, which removes sensor noise and small real motion alike; filtertype='Regular'; and the per-clip normalisation above.
Nothing is smoothed by default. The whole default chain is format=gray → tblend=all_mode=difference → threshold, and the smoothing that exists is off unless asked for — atadenoise (adaptive temporal averaging over 129 frames, the only temporal one), use_median (spatial), blur (spatial). A machine-analysis configuration is a matter of threshold and normalize, not of turning filters off.
MGT-python 1.9.2
Added
musicalgestures.__version__. The package exposed no version attribute
at all, so code could only learn the version through the installed
metadata, and a script run against a source checkout could not learn it
at all.
Fixed
- The version has one source.
pyproject.tomlreads
musicalgestures.__version__through a dynamic version rather than
carrying its own copy, so adding the attribute did not create a second
number to drift. That drift is not hypothetical across these toolboxes:
ambiscape shipped three releases reporting a version other than their
own and musiscape shipped one, in both cases because a bump edited
pyproject.tomlalone.tests/test_version.pyfails if a static
version reappears there, if the build stops reading the module
attribute, or if the two numbers diverge.
1.9.1 — issue fixes
1.9.0 — 360 directional analysis
Anglegrams, audio-energy-map overlays, perspective views, and projection auto-detection on Mg360Video; API docs migrated to mkdocstrings; documentation overhauled. See CHANGELOG.md.
1.8.0 — group QoM returns a different number, and the old one was confounded
group_qom, pose_qom and normalized_qom return different numbers. They are re-exported from micromotion, which released 1.0.0 today, and this is a correctness fix rather than a refinement.
They averaged over every marker at every frame while the underlying band_limited_qom interpolates gaps, so an occluded marker contributed a near-zero speed and still counted in the divisor. The result tracked how much the cameras saw rather than how much the body moved.
Twelve markers with a realistic dropout pattern, a median of eight visible: 78.07 against a true 91.53, with the speed series correlating +0.246 with the per-frame count of visible markers. The new default, normalize="visible", gives 90.85 at −0.001.
Pass normalize="worn" to reproduce a figure published with an earlier release, and say which you used. Clean pose data with no dropouts is unaffected; occluded mocap is affected most.
The micromotion floor is now >=1.0.0. That is a correctness floor rather than a documentation one: below it the re-exported function returns the confounded number.
All 545 tests pass against micromotion 1.0.0 unchanged, which also means none of them covered the behaviour that changed. The occlusion tests live upstream.
1.7.1 — the published API pages described a band this package no longer uses
Documentation and packaging. No behaviour changed.
Fixed
The committed API pages showed group_qom(points, fs, lo=0.3, hi=15.0) and deep-linked into musicalgestures/_qom.py at line numbers that stopped existing when those functions moved to micromotion on 2026-07-29. They are regenerated from the current source. The band is micromotion.BAND, 0.2–5 Hz.
docs/user-guide/pose-tracking.md and docs/user-guide/sound-movement-toolkit.md said 0.3–5 Hz, and one passed lo=0.3, hi=15.0 in an example a reader would copy. The regeneration script does not touch hand-written pages, so these were corrected by hand.
The micromotion requirement was >=0.3. No such release exists on PyPI below 0.6, and the functions re-exported here arrived far later, so the constraint permitted installations in which from musicalgestures import group_qom fails. It is now >=0.15.2, which is also the floor that makes the committed API pages true, since they are generated from that package's docstrings.
Changed
The three re-export shims now point at https://fourms.github.io/micromotion/. Their generated pages describe the shim rather than the functions, which is correct but left a reader with nowhere to go.
545 tests pass, on Python 3.10 to 3.12 across Linux, macOS and Windows.
v1.7.0
Fifty-six commits since 1.6.9, and the version had not moved with them.
The substantial additions are GoPro MAX .360 support: dual-fisheye output with the field of view as a parameter, and a time-average straight to a dual-fisheye image that samples before the remap rather than after — about fifteen times faster for an identical result. Both were written for a year of daily standstill recordings and have now run over all 365 of them.
Also fixes a temp-directory leak: the remap-table scratch directories were created in four places and removed in none, and a build over 364 recordings left 22 GB across 348 directories. cv2.imwrite failures are no longer discarded either, which is how a full disk used to surface as a corrupt-looking image several steps later. Three regression tests.
545 tests pass.