Skip to main content

BodyCompress

This library compresses and serializes the output of nonparametric 3D human mesh estimators such as Neural Localizer Fields (NLF) to disk.

Without compression, a sequence of 3D human meshes extracted from a video can take up huge amounts of disk space, as we need to store the coordinates for thousands of vertices in every frame. At 30 fps and 6890 vertices (like SMPL), this amounts to almost 9 GB/person/hour. If you want to save the estimation result for a multi-person video, it will be proportionally more.

This library achieves a compression ratio of over 8x on temporal human mesh data, with minimal loss in information. It consists of the following steps:

  1. Quantization: The floating-point coordinates of the vertices are quantized at 0.5 mm resolution.
  2. Vertex Reordering: The vertices are transparently reordered with a bundled TSP-optimized order (auto-detected for SMPL and SMPL-X) so that consecutive vertices are spatially adjacent, which makes the differential encoding more effective. The original order is restored on decompression.
  3. Differential Encoding: The quantized coordinates are differentially encoded in the (reordered) vertex order, so the differences between adjacent vertices tend to be small.
  4. Serialization: msgpack-numpy is used to serialize the NumPy arrays to a byte stream.
  5. Compression: The serialized byte stream is compressed losslessly with xz (LZMA), using the multi-threaded lzma-mt library, which is reasonably fast at compression level 5. (The Python standard library lzma module does not have multi-threading support and is too slow for our use case.) Alternatively, zstd compression can be selected for faster (de)compression at a somewhat lower compression ratio.

The format supports storing additional metadata in the header, and several per-frame pieces of information, such as vertices, joints, uncertainties, and camera parameters, compressing it all into one sequentially readable file.

Installation

pip install bodycompress

Usage

Use the BodyCompressor and BodyDecompressor classes to compress and decompress the data. The compressor should be used as a context manager and has an append method which should be called with keyword arguments. The decompressor is an iterable over dictionaries with the same keys; it also knows the number of frames upfront (len(bdecompr)) and can be iterated multiple times (each pass decompresses the file again from the start).

Note that seeking is not supported, the stream is compressed as a whole to achieve the best compression ratio.

Compression

from bodycompress import BodyCompressor

with BodyCompressor('out.xz', metadata={'whatever': 'you want'}) as bcompr:
    for frame in frames:
        vertices, joints = estimate(frame)
        bcompr.append(vertices=vertices, joints=joints)

Any keyword arguments can be passed to append that are nested dicts/lists/tuples of primitive types or NumPy arrays. However the following keywords are handled specially:

  • vertices: a (..., num_verts, 3) NumPy array of vertex coordinates (in millimeters)
  • joints: a (..., num_joints, 3) NumPy array of joint coordinates (in millimeters)
  • vertex_uncertainties: a (..., num_verts) NumPy array of vertex uncertainties (in meters)
  • joint_uncertainties: a (..., num_joints) NumPy array of joint uncertainties (in meters)
  • camera: a deltacamera.Camera object (or a dict in the format produced by bodycompress.cam_to_dict)

Coordinates are expected in millimeters; a warning is issued if the data looks like it might be in meters (i.e., its value range is tiny compared to the quantization step).

Input is validated and consumed synchronously in append: invalid data (NaN coordinates, malformed cameras, unserializable values) raises immediately without invalidating the file, so you can skip the offending frame and keep going, and you may freely reuse or overwrite the passed arrays after append returns. Only the final compression runs in a background thread; if that fails, the file is finalized with the frames written so far when possible.

If an exception is raised inside the with block, the partially written (unusable) file is deleted. If a compressor is never closed, it is finalized at interpreter exit and a ResourceWarning is emitted; don't rely on this, use the context manager or call close().

Useful options of BodyCompressor (see the API reference for the full list):

  • quantization_mm=0.5: coordinate resolution; coarser quantization gives smaller files
  • compression='xz': pass 'zstd' for much faster compression at a somewhat lower ratio
  • compression_level=None: defaults to 5 for xz and 3 for zstd
  • n_threads=0: number of compression threads (0 = auto-detect CPU count)

Decompression

from bodycompress import BodyDecompressor

bdecompr = BodyDecompressor('out.xz')
print(bdecompr.metadata)  # {'whatever': 'you want'}
print(len(bdecompr))  # number of frames
for data in bdecompr:
    render(data['vertices'], data['joints'])

Stored cameras are yielded as plain dicts by default; pass decode_camera=True to BodyDecompressor to get deltacamera.Camera objects back.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bodycompress-0.3.0.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bodycompress-0.3.0-py3-none-any.whl (49.0 kB view details)

Uploaded Python 3

File details

Details for the file bodycompress-0.3.0.tar.gz.

File metadata

  • Download URL: bodycompress-0.3.0.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for bodycompress-0.3.0.tar.gz
Algorithm Hash digest
SHA256 87acafc3eebb03bbc1a84990431d0addfbe2806f3193285035d7a6aad9c67358
MD5 062041a7cb56b87eceb220b98bcb7f10
BLAKE2b-256 237e378287da44f8db13bb940d77bafb1a8dc7d34f6905b525d365c6b26c4794

See more details on using hashes here.

Provenance

The following attestation bundles were made for bodycompress-0.3.0.tar.gz:

Publisher: python-publish.yml on isarandi/bodycompress

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bodycompress-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: bodycompress-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 49.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for bodycompress-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 19af32b9da8766a2c81315fb4de565f730e7a5433daf54e12ce7a32c4b17a616
MD5 fe5ce18904c05524002a51b04a29f470
BLAKE2b-256 29ce06403ec70a31b5e4a9428872f339508e83cbb64d12223eea77a3aa8fa13f

See more details on using hashes here.

Provenance

The following attestation bundles were made for bodycompress-0.3.0-py3-none-any.whl:

Publisher: python-publish.yml on isarandi/bodycompress

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page