Skip to main content

asl-mri-utils

Command-line tools for post-processing Siemens arterial spin labeling (ASL) MRI data: recovering true acquisition order from DICOM, converting to NIfTI, splitting timeseries by TI/label/control, and computing perfusion-weighted difference images.

Siemens-only by design. The whole pipeline reads the true LABEL/CONTROL/M0/TI order straight from per-frame DICOM tags, not from filenames or protocol names, so it needs the Siemens tags that provide that: the standard ASL DICOM tags plus one Siemens private tag for TI ordering. If an expected tag is missing, a command raises a specific exception rather than guessing.

Table of contents

Install

pip install asl-mri-utils

For local development, from a clone of this repository:

pip install -e .

Requirements

Tool Needed for Not found?
dcm2niix or dcm2niix_afni convert (always) convert fails -- not bundled, must be installed separately
AFNI (3drefit) convert's slice-timing embedding skipped silently, not an error
AFNI (3dvolreg, 3dAllineate, 1dplot) subtract --mc / --split-mc subtract --mc fails -- not bundled (1dplot only makes the motion plot; optional)

Each external binary is found via an explicit flag first, then an environment variable, then PATH: --dcm2niix-bin/$ASL_MRI_UTILS_DCM2NIIX for dcm2niix, --afni-bindir/ $ASL_MRI_UTILS_AFNI_BINDIR (a directory) for the AFNI programs.

Quickstart

A typical run, starting from one Siemens ASL series' exported DICOM folder:

# 1. See what dcm2niix would even produce: LABEL/CONTROL/M0 order, TI index, and timing,
#    read straight from the DICOM headers.
asl-mri-utils order 021-my_asl_series

# 2. Convert that series to NIfTI, per echo. This also builds each echo's oxasl-ready
#    *_asl.nii.gz/*_mzero.nii.gz and oxasl_params.json.
asl-mri-utils convert 021-my_asl_series ./niftis

# 3. (Optional) Split echo 1 into per-TI, per-label/control NIfTIs -- useful to inspect, or to
#    hand to other tools directly.
asl-mri-utils split ./niftis/021_my_asl_series_echo-01_asl.nii.gz \
                     ./niftis/021_my_asl_series_echo-01_order.tsv

# 4. Compute perfusion-weighted difference images. --mc motion-corrects first; --mean adds a
#    temporal-mean companion to every diff file (the actual perfusion-weighted map).
asl-mri-utils subtract ./niftis/021_my_asl_series_echo-01_asl.nii.gz \
                        ./niftis/021_my_asl_series_echo-01_order.tsv \
                        --mc --mean

(The *_asl.nii.gz files above only exist when convert had something to remove -- M0 volumes or a trailing unpaired block. Otherwise use the raw *_echo-01.nii.gz, which oxasl_params.json's asl_file names; a dedicated M0 series yields only *_mzero.nii.gz.)

Step 3 is optional: subtract does not need split's output. Running it separately just lets you inspect the per-TI/label/control NIfTIs on their own, e.g. in fsleyes or afni.

Commands

order: recover acquisition order

Recovers the true LABEL/CONTROL/M0/TI acquisition order of a Siemens ASL series directly from per-frame DICOM tags (ASL Context, a Siemens private ordering tag), independent of filenames or protocol names. Writes one order.tsv per echo: volume_index, echo, ti_index, temporal_index, asl_context, acq_time, delta_t (seconds since the first image).

asl-mri-utils order <dicom_series_dir> [<dicom_series_dir> ...] [--outdir DIR]
asl-mri-utils order --all [ROOT] [--outdir DIR]

convert: DICOM to NIfTI

Wraps a local dcm2niix/dcm2niix_afni install to convert one series directory to NIfTI, entirely per echo. For each echo, writes:

  • the raw NIfTI + JSON sidecar, renamed to this package's own *_echo-0N convention
  • *_echo-0N_order.tsv (same schema as order, above)
  • an oxasl-ready *_echo-0N_asl.nii.gz (label/control volumes) and *_echo-0N_mzero.nii.gz (M0 volumes), with a matching *_echo-0N_aslcontext.tsv. The _asl file is only written when it removes something from the raw file (M0 volumes or a trailing unpaired block); a series with neither is already oxasl-ready as-is, and oxasl_params.json's asl_file points at the raw NIfTI. A dedicated M0 series (folder name has an M0 token, or --m0-series) gets only _mzero.nii.gz. oxasl_params.json is the source of truth for which files to feed oxasl.
  • *_echo-0N_oxasl_params.json, recording the (iaf, order, ntis, tis_ms, rpts) shape oxasl needs. tis_ms comes from --slice-timing FILE (the sequence's TimingInfo file, which also gives per-slice TIs), else --tis, else the DICOM header where the protocol stored it there; otherwise null, with a note explaining why, not a guess.

If an AFNI install is available and the JSON sidecar has a SliceTiming field, that's also burned into every NIfTI's header via 3drefit -Tslices.

asl-mri-utils convert <in_dir> <out_dir> [--dcm2niix-bin PATH] [--overwrite] [--m0-series | --no-m0-series]

split: per-TI, label/control timeseries

Splits one echo's timeseries into per-TI NIfTIs, each further split into its label-only and control-only subseries:

<stem>_TI<k>.nii.gz          # that TI's label+control volumes, chronological order
<stem>_TI<k>_label.nii.gz    # that TI's label volumes only
<stem>_TI<k>_control.nii.gz  # that TI's control volumes only

Point it at either the raw per-echo timeseries from convert, or its *_asl.nii.gz -- either way, pass the matching order.tsv. Which one you gave it is detected automatically, from its own volume count.

asl-mri-utils split <nii> <order_tsv> [--echo N] [--ti N ...] [--outdir DIR]

subtract: perfusion-weighted difference images

Computes a perfusion-weighted difference image per TI. Like split, it accepts either the raw timeseries or *_asl.nii.gz.

The default method, simple, is just label - control and its negation (the same decimated pairs as standard, written as *_LCdiff/*_CLdiff). Pass --methods standard surround sinc instead for Liu & Wong (2005, NeuroImage 24:207-215) pairwise/surround/sinc subtraction -- three different ways of handling the tradeoff between temporal resolution and noise when differencing an alternating label/control series. --recommend block|event_related picks one of those three automatically, per the paper's own guidance, instead of listing --methods by hand.

  • --methods running: pairwise difference at every adjacent label/control pair (2N-1 outputs), vs standard's decimated pairs (N outputs). surround and sinc also give one output per acquired volume. No method adds information, and full-rate outputs are autocorrelated (lag-1 ~0.5 running, ~0.67 surround, ~0.64 sinc, ~0 standard) in a way that cannot be prewhitened (spectral nulls of the filter), so fit the unsubtracted data or use decimated standard pairs. See docs/subtract.md for the L C L C illustration.
  • --combine diff|avg|both|auto: besides the perfusion difference (control - label), write the BOLD-weighted average (control + label) / 2 through the same filter (*_avg.nii.gz). auto writes the difference for the lowest echo and the average for later echoes. Full-rate averages cannot be prewhitened any more than the differences can; for BOLD statistics use the raw later-echo data or the decimated standard --combine avg with an AR fit.
  • --grid midpoint: sinc interpolates both conditions to the midpoints between volumes.
  • --label-first: write the difference as label - control (files get an _LC suffix) for sequences where the label image is the brighter one. Sign convention only; see docs/subtract.md.
  • --mc: motion-correct the whole timeseries first (AFNI 3dvolreg, base volume 0), then split into TIs and label/control from the corrected file. Every output is then named off the resulting _volreg file. Also saves *_volreg.aff12.1D (matrices), *_volreg_motion.1D and a motion plot. On a multi-echo dataset, run the lowest echo first: --mc on every other echo then automatically applies that echo's *_volreg.aff12.1D (3dAllineate), so all echoes share one motion estimate.
  • --split-mc: like --mc (implies it), but estimate motion in two passes -- controls registered to control volume 0, labels registered to that same control volume 0 -- then interleave back to the original volume order. Saves the same *_volreg.aff12.1D (one matrix per original volume), which other echoes apply unchanged.
  • --mean / --tsnr: add a temporal-mean, or temporal-mean/temporal-std, companion to every diff file produced. --mean's output is the perfusion-weighted map most people actually want.
  • --sinc-interp: for the sinc method only, swap its estimator for an alternative (windowed-sinc, FFT, Gaussian process regression, or a Kalman filter/RTS smoother -- see docs/interpolate.md).
asl-mri-utils subtract <nii> <order_tsv> [--ti N ...]
    [--methods simple|standard|running|surround|sinc ...] [--recommend block|event_related]
    [--combine diff|avg|both|auto] [--grid sample|midpoint] [--label-first]
    [--sinc-interp truncated|windowed_sinc|fft|gp|kalman]
    [--mc | --split-mc] [--afni-bindir DIR] [--mean] [--tsnr] [--outdir DIR]

glm: OLS on subtracted ASL, corrected for the filter

asl-mri-utils glm <nii> <order_tsv> --method surround --design regressors.tsv --contrast act=perfact_ti1:1 fits contrasts on the subtracted series of each TI with the variance and degrees of freedom corrected for the subtraction filter (FEAT's perfusion-subtraction route, which cannot use prewhitening because the filter's correlation has spectral nulls). It builds the filter from the raw volumes, passes the design through it (a ti<k> baseline is annihilated and dropped, perf_ti<k> becomes the intercept), and writes *_cope/*_varcope/*_tstat maps plus a *_glm.json with the effective degrees of freedom. It warns when the brain-mean C/L differs from 1 by more than 2% (BOLD then leaks into the perfusion contrast). See docs/glm.md and docs/filters.md.

regressors: design columns for unsubtracted ASL

asl-mri-utils regressors <nii> <order_tsv> writes <stem>_regressors.tsv: per volume, the control/label modulation (+0.5 / -0.5, 0 for M0) and, per TI, a baseline indicator ti<k> and a perfusion modulation perf_ti<k>, for fitting the unsubtracted data in FEAT or AFNI (Mumford et al. 2006, NeuroImage 33:103-14) with an AR noise model (FILM / 3dREMLfit).

--task NAME=FILE (repeatable; onset duration [amplitude] per line, seconds) adds FEAT's full-model EVs per TI, at each volume's true acquisition time: bold_ti<k>_NAME (task x HRF) and perfact_ti<k>_NAME (task x perf_ti<k>). --format afni|fsl|all also exports .1D / per-EV text files. See docs/perfusion-fmri.md.

lcratio and autocorr: noise and contrast diagnostics

asl-mri-utils lcratio <nii> <order_tsv> reports the brain-mean label/control ratio per TI and warns about a large static difference (BOLD leaking into the perfusion contrast) or a negative C - L. asl-mri-utils autocorr <nii> <order_tsv> [--method running] maps the residual autocorrelation (raw, or through a subtraction filter next to the filter's exact value). See docs/autocorr.md.

betas2oxasl, s0r2star, convert --m0

betas2oxasl stacks per-TI GLM betas into oxasl-ready differenced ASL (TIs, bolus, slice timing, M0 in a params JSON); s0r2star fits two-echo S0 and R2*; convert --m0 links a separately acquired M0 with its phase-encoding direction and a geometry check. See docs/perfusion-fmri.md.

discover: find series directories

Finds candidate DICOM series directories under a root, matching the NNN-SeriesDescription folder convention order --all/convert expect.

asl-mri-utils discover [ROOT]

Further reading

Each module has its own page under docs/, with the implementation detail this README leaves out (exact DICOM tags, the Liu & Wong equations, worked examples):

Doc Covers
docs/dicom.md Siemens tag reading, the ASL Context classification rule, header-derived TI values
docs/order.md Ordering/pairing logic, the order.tsv schema
docs/discovery.md Series discovery, DICM magic-byte sniffing
docs/binaries.md Shared external-binary resolution (dcm2niix, AFNI)
docs/convert.md dcm2niix wrapping, per-echo oxasl_params.json fields, slice-timing embedding
docs/merge.md Splitting one echo's output into its oxasl-ready asl/mzero pair
docs/split.md Per-TI, per-label/control timeseries splitting
docs/subtract.md The simple method, plus the Liu & Wong (2005) equations for standard/surround/sinc
docs/autocorr.md autocorr and lcratio noise diagnostics
docs/perfusion-fmri.md Perfusion fMRI analysis plan, task EVs, AFNI recipe
docs/interpolate.md Windowed-sinc, FFT, Gaussian process, and Kalman/RTS interpolation, with worked examples

Metadata

Release files for asl-mri-utils 0.18.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for asl-mri-utils 0.18.0
File Size Uploaded Provenance
asl_mri_utils-0.18.0.tar.gz 247.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for asl-mri-utils 0.18.0
File Interpreter ABI Platform
asl_mri_utils-0.18.0-py3-none-any.whl Python 3 none any Details

Total release size: 344.3 kB

Release files / asl_mri_utils-0.18.0.tar.gz

Download URL asl_mri_utils-0.18.0.tar.gz
Size 247.5 kB
Tags Source
SHA-256 checksum
How to use checksums
632959c8eddd03ffdd5ebd7540cecf698abeb4a39800bccaf8ec447fc12c516d
BLAKE2b-256 checksum
How to use checksums
09e5d1f05722f5ee706c68563f42fdead799e1ef3f6e52bea83a22fdf2fcf78b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / asl_mri_utils-0.18.0-py3-none-any.whl

Download URL asl_mri_utils-0.18.0-py3-none-any.whl
Size 96.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0c1e7c0ae0b9ce5c73529effd71ff7dfeb22a827a13fcb107c8c01ecfa00fbf1
BLAKE2b-256 checksum
How to use checksums
2157a2b166fe0126b7250711fcdb4fff6443d3fc7c52359701382bce665bef2e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for asl-mri-utils 0.18.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for asl_mri_utils-0.18.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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