livephoto-motion
Measure how a short video clip moves — not just how much.
Two numbers, from plain frame differencing:
MVI — Motion Volatility Index. Overall change between frames, split into a global component (the whole frame shifting, which is what camera movement looks like) and a local component (a subject moving inside a frame that stays put).
MSI — Motion Surface Index. How much of the frame is moving, plus an edge ratio flagging movement concentrated at the borders rather than the middle.
The split is the useful part. Two clips can score identically for total movement while one is a locked camera watching someone wave and the other is a handheld shot of nothing in particular.
Install
pip install livephoto-motion
ffmpeg must be on your PATH for file decoding. The index maths itself has no
dependencies at all.
Use
from livephoto_motion import measure
r = measure("clip.mov")
print(r.mvi.score, r.mvi.global_, r.mvi.local) # 7.85 0.91 8.27
print(r.msi.score, r.msi.edge_ratio) # 5.83 0.28
Or from the shell:
livephoto-motion clip.mov
livephoto-motion clip.mov --json
Already have frames? Skip ffmpeg entirely — compute_indices takes any
sequence of 8-bit grayscale frames, from PyAV, OpenCV, or a fixture:
from livephoto_motion import compute_indices
indices = compute_indices(frames, width=96, height=160)
Where this came from
It was written to answer a narrow question: which Live Photos will iOS accept as an animated iPhone Lock Screen wallpaper. Measuring clips confirmed to animate on a device, movement within the frame runs far higher than movement of the frame — a locked camera with an active subject, rather than a little movement overall.
Two honest limits on that observation. The sample is small, and it contains no confirmed failures, so it describes a known-good range rather than a measured threshold. This package therefore reports measurements and does not grade them.
None of the maths is iOS-specific and it applies to any short clip. If you want the format side of that question — the seven things iOS checks before it will animate a Live Photo — that lives in a separate library, livephoto-check, with a hosted version at lockimate.com/tools/live-photo-check.
How it works
Frames are decoded to 96×160 grayscale and sampled evenly across the clip — twelve samples capture the shape of the movement at a fraction of the work of every frame. For each consecutive pair:
- the median absolute difference tracks whole-frame change, so it rises when the camera moves and stays near zero when it does not
- the spread between the 95th percentile and the median tracks concentrated change, which is a subject moving
- pixels differing by more than 8 levels count as moving area, which keeps encoder noise out of the measurement
- the outer 15% of the frame is treated as the edge band for the edge ratio
Tests
pip install -e ".[dev]"
pytest
The maths is pure, so the suite uses synthetic frames and ships no fixtures.
Licence
MIT.
Metadata
Release files for livephoto-motion 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| livephoto_motion-0.1.0.tar.gz | 7.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| livephoto_motion-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.5 kB
Release files / livephoto_motion-0.1.0.tar.gz
| Download URL | livephoto_motion-0.1.0.tar.gz |
|---|---|
| Size | 7.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ebe9393d636d1579c02ccf4b4c6b4899738d15b105d3a56cb64fec5b039f47cd
|
|
BLAKE2b-256 checksum How to use checksums |
9d7fc429e6fe5add6c202b64f7d57ae11e36c47910cf457ff5807d3ef8f3e157
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / livephoto_motion-0.1.0-py3-none-any.whl
| Download URL | livephoto_motion-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31eb505cde38e9e55e0f9c4f612306a7484ae57b17ba0353698b91e7e38d8395
|
|
BLAKE2b-256 checksum How to use checksums |
b1c4884ad5d8fee40c5460282eb2cbfe07f7b7dfaaed860a33c1be013eb31fee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|