Skip to main content

Lightweight converter for motion data to BIDS format

Project description

motionbids

PyPI Python License: MIT Tests codecov

A lightweight Python package for exporting motion capture data to BIDS format.

Quick Start

from motionbids import MotionData, Channel, export_bids_motion
import numpy as np

# Your motion data (1200 timepoints, 32 channels)
data = np.random.randn(1200, 32)

# Define channels following BIDS schema
channels = [
    Channel(
        channel_name=f"marker{i}_{axis}",
        channel_component=axis,
        channel_type="POS",
        channel_tracked_point=f"marker{i}",
        channel_units="mm"
    )
    for i in range(10)
    for axis in ['x', 'y', 'z']
]

# Create BIDS motion object
motion = MotionData(
    subject="01",
    task_name="walk",
    tracksys="optical",
    sampling_frequency=120.0,
    tracked_points_count=10,
    manufacturer="Vicon",
    data=data,
    channels=channels
)

# Export to BIDS format
export_bids_motion(motion, out_dir="bids_dataset/")

Output:

bids_dataset/
├── sub-01_task-walk_tracksys-optical_motion.json      # Metadata
├── sub-01_task-walk_tracksys-optical_motion.tsv       # Time series
└── sub-01_task-walk_tracksys-optical_channels.tsv     # Channel info

Installation

pip install motionbids

Or with uv:

uv pip install motionbids

For development:

git clone https://github.com/JuliusWelzel/motionbids.git
cd motionbids
pip install -e ".[dev]"

Features

Schema-driven - Auto-syncs with BIDS specification
Automatic validation - Catches errors before export
Simple API - Minimal code needed
Complete export - JSON, TSV, channels files
Cross-platform - Tested on Linux, macOS, Windows

Documentation

Full Documentation

Required Fields

motion = MotionData(
    subject="01",              # Subject identifier
    task_name="walk",             # Task name
    tracksys="optical",           # Tracking system (optical/imu/video)
    sampling_frequency=120.0,     # Sampling rate in Hz
    tracked_points_count=10,      # Number of markers
    data=data,                    # NumPy array (rows=time, cols=channels)
    channels=channels             # List of Channel objects (BIDS-compliant)
)

Channel Metadata

Each channel requires BIDS-compliant metadata:

from motionbids import Channel

channel = Channel(
    channel_name="marker0_x",           # Channel name
    channel_component="x",              # x, y, z, quat_x, quat_y, quat_z, quat_w, n/a
    channel_type="POS",                 # POS, ORNT, VEL, ACCEL, GYRO, MAGN, etc.
    channel_tracked_point="marker0",    # Label of tracked point
    channel_units="mm"                  # Units (mm, m, rad, deg, etc.)
)

Validation

Important: Package validation is for convenience only and is not officially supported by BIDS. Always use the official BIDS Validator before sharing your dataset.

from motionbids import validate_motion_data

# Convenience validation (checks basic requirements)
validate_motion_data(motion)

# Then validate with official BIDS Validator:
# https://bids-standard.github.io/bids-validator/

Complete Workflow

from motionbids import (
    MotionData,
    export_bids_motion,
    create_bids_directory_structure,
    export_dataset_description
)

# 1. Create directory structure
motion_dir = create_bids_directory_structure(
    base_dir="my_study",
    subject="01",
    session="01"
)

# 2. Create dataset description
export_dataset_description(
    bids_root="my_study",
    name="Motion Study",
    authors=["Your Name"]
)

# 3. Export motion data
motion = MotionData(...)
export_bids_motion(motion, out_dir=motion_dir)

Supported Systems

Works with any motion tracking technology:

  • Optical: Vicon, Optitrack, Qualisys
  • IMU: Xsens, APDM, Movella
  • Video: OpenPose, MediaPipe, DeepLabCut
  • Other: Custom systems

Importing Data

motionbids focuses on exporting to BIDS format. Importing raw data is left to the user since motion capture systems vary widely. Here are common patterns:

From CSV / TSV

import pandas as pd
import numpy as np
from motionbids import MotionData, Channel

# Load your data
df = pd.read_csv("recording.csv")
data = df.values

# Map columns to BIDS channels
channels = [
    Channel(
        channel_name=col,
        channel_component=col.split("_")[-1],  # e.g. "x", "y", "z"
        channel_type="POS",
        channel_tracked_point=col.rsplit("_", 1)[0],
        channel_units="mm"
    )
    for col in df.columns
]

motion = MotionData(
    subject="01", task_name="walk", tracksys="optical",
    sampling_frequency=120.0, tracked_points_count=10,
    data=data, channels=channels
)

From C3D (requires ezc3d)

import ezc3d
import numpy as np
from motionbids import MotionData, Channel

c3d = ezc3d.c3d("recording.c3d")
points = c3d["data"]["points"]  # (4, n_markers, n_frames)
labels = c3d["parameters"]["POINT"]["LABELS"]["value"]
freq = c3d["parameters"]["POINT"]["RATE"]["value"][0]

# Reshape to (n_frames, n_channels)
data = points[:3, :, :].transpose(2, 1, 0).reshape(-1, len(labels) * 3)

channels = [
    Channel(
        channel_name=f"{label}_{axis}",
        channel_component=axis,
        channel_type="POS",
        channel_tracked_point=label,
        channel_units="mm"
    )
    for label in labels
    for axis in ["x", "y", "z"]
]

motion = MotionData(
    subject="01", task_name="walk", tracksys="optical",
    sampling_frequency=freq, tracked_points_count=len(labels),
    data=data, channels=channels
)

See the Workflow Guide for more patterns.

Development

git clone https://github.com/juliuswelzel/motionbids.git
cd motionbids
pip install -e ".[dev]"

# Run tests
pytest --cov=motionbids

Citation

@software{motionbids,
  author = {Welzel, Julius},
  title = {motionbids: BIDS converter for motion capture data},
  year = {2026},
  url = {https://github.com/JuliusWelzel/motionbids}
}

Links

License

MIT License - see LICENSE for details.

Project details


Download files

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

Source Distribution

motionbids-0.4.0.tar.gz (395.7 kB view details)

Uploaded Source

Built Distribution

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

motionbids-0.4.0-py3-none-any.whl (24.1 kB view details)

Uploaded Python 3

File details

Details for the file motionbids-0.4.0.tar.gz.

File metadata

  • Download URL: motionbids-0.4.0.tar.gz
  • Upload date:
  • Size: 395.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.19

File hashes

Hashes for motionbids-0.4.0.tar.gz
Algorithm Hash digest
SHA256 9246cf32d74c8a14d021604bc488a6c554ed1b03161975362a4611563b652c5e
MD5 4f57cad7e8bcc051ca7a4c409f003343
BLAKE2b-256 04ed85bbbd6a61e6b52f32e58365c543aa32f199c091ff6942be76b3c2af6275

See more details on using hashes here.

File details

Details for the file motionbids-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: motionbids-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 24.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.19

File hashes

Hashes for motionbids-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 261aa214965e293f645e43a7536d54e9fcea0fe108dc376264b318046b29abd6
MD5 3cc336895a3c373780f450ca74fd57ee
BLAKE2b-256 ceb4a5aafc96f8eaba0299dcbeab58b93a76171c36cf55525883aa77975d50bc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page