Skip to main content

Eye voxel extraction pipeline using templated eye masks.

Project description

License: GPL v3 py311 status NatNeuro Paper DeepMReye

MReyeXtract: eye-voxel extraction for fMRI

Image of a brain with masks

MReyeXtract extracts the eyeballs from 4D BOLD images so they can be fed to DeepMReye or other gaze-decoding models. Each run is registered to a DeepMReye eye template with ANTsPy, cropped to the eye masks, and saved alongside an interactive HTML quality-control report. It runs on BIDS datasets out of the box, and on arbitrary directory trees via a glob pattern.

If you have questions or comments, please reach out (see Correspondence).

Installation

MReyeXtract requires Python 3.11.

Option 1: Pip install

Pip installation

python3.11 -m venv .venv
source .venv/bin/activate
pip install -e .

For development (tests, linting, type checking):

pip install -e ".[dev]"

Anaconda / Miniconda installation

conda create --name mreyextract python=3.11
conda activate mreyextract
pip install -e .

If ANTsPy does not resolve a wheel for your platform, install it manually first (see the ANTsPy installation guide) and then re-run the install above.

Usage

Installing the package exposes the mreyextract command-line tool. Run mreyextract --help for the full list of options.

BIDS datasets (default)

mreyextract --root /path/to/bids_dataset

To extract from a derivatives pipeline (e.g. fMRIPrep outputs):

mreyextract --root /path/to/bids_dataset --derivatives-dir fmriprep

Restrict which BOLD files are processed with BIDS entities. Each accepts one or more values; '*' matches any value and 'none'/'null' matches files where the entity is absent:

mreyextract --root /path/to/bids_dataset \
            --subject 01 02 --task rest --run '*'

Filters can also be supplied as a JSON file via --bids-filter-file (the BIDS-App convention). Precedence, lowest to highest, is: YAML config (see later) → JSON BIDS filter file → explicit CLI entity flags, so the command line always wins.

Non-BIDS directories

Point --no-bids-compatible at any tree and provide a glob pattern:

mreyextract --root /path/to/data --no-bids-compatible \
            --glob-pattern 'sub-*/**/func/*_bold.nii*'

Options

Option Description
--root Root directory to search for BOLD files (required).
--bids-compatible / --no-bids-compatible Treat --root as a BIDS dataset. Default: BIDS.
--derivatives-dir Relative derivatives directory to extract from (e.g. fmriprep).
--glob-pattern Glob for non-BIDS mode. Default: sub-*/**/func/*_bold.nii*.
--force Overwrite existing outputs instead of skipping them.
--as-pickle Save the masked eye voxels as a pickled array instead of NIfTI.
--n-jobs Number of runs to process in parallel. 1 (default) is serial; -1 uses all cores.
--threads-per-job ITK/ANTs threads per parallel job. Default: cores // n_jobs.
--log-level Logging verbosity: DEBUG, INFO, WARNING, ERROR. Default: INFO.
--bids-filter-file Path to a JSON file of BIDS entity filters.
--config Path to a YAML config file that seeds the options above.

Config file

Rather than passing many flags, the run can be described in a YAML file and loaded with --config. Keys under extract mirror the CLI options (with underscores); explicit flags on the command line override the file:

# run.yaml
extract:
  root: /abs/path/to/bids_dataset
  derivatives_dir: fmriprep
  n_jobs: 4
  threads_per_job: 2
  filters:
    task: [rest]        # "*" -> any, "none"/"null" -> absent
mreyextract --config run.yaml            # everything from the file
mreyextract --config run.yaml --force    # override a single option

Parallel processing

Runs are independent, so they can be processed in parallel across a loky process pool:

mreyextract --root /path/to/bids_dataset --n-jobs 8

Registration (ANTsPy/ITK) is itself multithreaded, so the tool splits the available cores between across-run parallelism (--n-jobs) and each run's own threads (--threads-per-job) to avoid oversubscription. By default threads-per-job is set to cores // n_jobs, where cores respects the CPU allocation (SLURM/cgroup affinity), not just the physical node — so the default is safe when running interactively inside an allocation. Tune both together on a shared server, and keep an eye on memory — each concurrent run holds a full 4D BOLD volume in RAM.

Python API

The extraction entry point can also be called directly:

from mreyextract.extract import extract_eyeball_voxels

extract_eyeball_voxels(
    root="/path/to/bids_dataset",
    glob_pattern="sub-*/**/func/*_bold.nii*",
    bids_compatible=True,
    filters={"task": "rest"},
)

Data formats

Inputs are 4D BOLD images in NIfTI format (.nii / .nii.gz). Outputs are written to a BIDS-style derivatives folder under the dataset root:

<root>/derivatives/mreyextract/
    dataset_description.json
    sub-01/func/
        sub-01_task-rest_run-1_desc-eye_bold.nii.gz   # masked eye voxels
        sub-01_task-rest_run-1_desc-eye_report.html   # QC report

With --as-pickle, the eye voxels are saved as a pickled NumPy array (*_desc-eye_timeseries.p) instead of NIfTI. Existing outputs are skipped unless --force is passed.

Hardware requirements

Registration is CPU-based and runs per BOLD run. A standard workstation is sufficient; no GPU is required. Memory scales with image size — 4D BOLD runs are held in memory during registration, so allow several GB of free RAM for high-resolution or long acquisitions.

Software requirements

MReyeXtract is developed and tested on Python 3.11. Core dependencies (installed automatically):

numpy      (<2.0.0)
nibabel    (>=5.3.2)
antspyx    (>=0.6.1)
scipy      (>=1.15.1)
plotly     (>=6.5.0)
pybids     (>=0.22.0)
joblib     (>=1.3)
pyyaml     (>=6.0)

Running on a cluster (SLURM)

The slurm/ directory contains a ready-to-adapt job-array template (submit.sbatch) and an example config.yaml. The pattern is one array task per subject: SLURM provides the across-subject parallelism, and each task lets ANTs use all of its allocated cores.

mkdir -p logs
sbatch slurm/submit.sbatch slurm/config.yaml

The template reads the subject list from the config's slurm.subjects, injects the right subject per array index, and caps ITK/OpenMP threads to --cpus-per-task. Edit the #SBATCH resource directives (and the --array range to match the number of subjects), the module load line (must be a Python 3.11 build), and the virtual-environment path before submitting.

Tests

pytest

Development

MReyeXtract is maintained as part of the OpenMReye ecosystem and is a dependency of other packages, so releases follow an automated, convention-based pipeline. Please read this section before contributing.

Local setup

python3.11 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Run the full check suite (mirrors CI) before pushing:

./format_and_test.sh          # black, mypy, pylint, tests

Branch and commit workflow

main is protected: no direct pushes. All changes land through pull requests that are squash-merged, so the PR title becomes the commit message on main. That title must be a valid Conventional Commit, because it is what drives the next version number:

PR title prefix Example Release effect
fix: fix: correct mask resampling origin patch (0.1.00.1.1)
feat: feat: add --as-pickle output minor (0.1.00.2.0)
feat!: / BREAKING CHANGE: feat!: drop Python 3.10 support major bump*
docs: / chore: / ci: / test: / refactor: docs: clarify SLURM template no release

*While the package is in 0.x (allow_zero_version, major_on_zero = false), a breaking change bumps the minor version rather than jumping to 1.0.0. Graduating to 1.0.0 is a deliberate decision to make once the API is stable, since downstream packages pin against these numbers.

The PR title is checked automatically (pr-title.yml); a malformed title blocks the merge.

How a release happens

The pipeline is fully automated and stores no secrets — you never bump a version or publish by hand:

  1. ci.yml runs the check suite on every PR. These are required status checks, so main is always green.
  2. On merge to main, release.yml runs. Its first job uses python-semantic-release: it reads the Conventional Commits since the last release, and if there is something to release, creates the vX.Y.Z git tag and a GitHub Release (whose notes are the changelog). It is configured not to commit or push to main, so the branch is never touched and the default GITHUB_TOKEN suffices. The version lives only in git tags and is read at build time by hatch-vcs.
  3. The workflow's second job then builds the sdist/wheel from that tag and uploads to PyPI via Trusted Publishing (OIDC — no PyPI token anywhere). It runs in the pypi deployment environment, so the upload waits on manual approval.

Pure docs:/chore: merges produce no release, so main does not spam PyPI.

BIDS app

MReyeXtract reads and writes BIDS-compatible layouts: it queries BOLD files with PyBIDS, honours BIDS entity filters, and emits a derivatives/mreyextract/ folder with a dataset_description.json.

Correspondence

If you have questions, comments or inquiries, please reach out to us: zachnudels[at]gmail.com

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

mreyextract-0.1.0.tar.gz (2.9 MB view details)

Uploaded Source

Built Distribution

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

mreyextract-0.1.0-py3-none-any.whl (2.9 MB view details)

Uploaded Python 3

File details

Details for the file mreyextract-0.1.0.tar.gz.

File metadata

  • Download URL: mreyextract-0.1.0.tar.gz
  • Upload date:
  • Size: 2.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mreyextract-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7f6fb7d566deb4cfe370f34a86d49335579c0ace959d7d2411edf993774534cd
MD5 c8334b4ede6428dcd31f1a0cfaa20e7e
BLAKE2b-256 821bab314b9d9283a693f8bde074e2569302b89e19b3ca034c43b19ea1338d61

See more details on using hashes here.

Provenance

The following attestation bundles were made for mreyextract-0.1.0.tar.gz:

Publisher: release.yml on DeepMReye/MReyeXtract

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

File details

Details for the file mreyextract-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mreyextract-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 2.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mreyextract-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 63bdb8cfeb5801bf31f1e9ed9d8596bf17defd95ffc7ffd8a7460c5d069680e9
MD5 5bd0b63fa2afc7a969dcde3bac31c720
BLAKE2b-256 481e07171664fe0ec582be5eacff8bc98388caff50b93d613cb519110da36e2e

See more details on using hashes here.

Provenance

The following attestation bundles were made for mreyextract-0.1.0-py3-none-any.whl:

Publisher: release.yml on DeepMReye/MReyeXtract

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

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