A Python library for neuroimaging transforms, focused on the Multi-Echo DIstortion Correction (MEDIC) algorithm. The pre-print is available at https://www.biorxiv.org/content/10.1101/2023.11.28.568744v1.
The phase-unwrapping core is a self-contained C++17 port of ROMEO — there is no Julia runtime to install, and binary wheels ship with the ITK pieces statically linked. If you used an older release of warpkit that required julia on PATH, that step is gone.
pip install warpkitPre-built wheels are published for Linux (x86_64 + aarch64) and macOS (universal2). If pip falls back to a source build and fails, please open an issue with the output of pip install warpkit -v.
Each GitHub release attaches a zip per arch (linux-x86_64, linux-aarch64, macos-arm64) containing all seven wk-* CLIs as standalone binaries — no Python install or system ITK needed. Extract, add to PATH, and run. See the bundled README.md inside the zip for install/PATH instructions and the macOS Gatekeeper note.
docker run -it --rm ghcr.io/vanandrew/warpkit:latest --helpThe image's entrypoint is the wk-medic CLI.
You need a C++17 compiler and CMake ≥ 3.24. Everything else (Python, build deps, ITK) is resolved by uv.
git clone https://github.com/vanandrew/warpkit.git
cd warpkit
uv sync --group dev --config-setting editable_mode=stricteditable_mode=strict is the recommended setuptools editable layout — it avoids the import-path pitfalls of the default editable install. Append -v to uv sync if a build fails and include the full log when reporting the issue.
MEDIC takes ME-EPI phase data:
and turns it into a per-frame field map:
You can then use these field maps to distortion-correct your data.
warpkit is meant to be integrated into a larger neuroimaging pipeline. The Python entry point:
import nibabel as nib
from warpkit.distortion import medic
from warpkit.utilities import displacement_map_to_field
# each list entry is a different echo
phases = [nib.load(p) for p in phases_paths]
magnitudes = [nib.load(p) for p in magnitude_paths]
TEs = [TE1, TE2, ...] # milliseconds
total_readout_time = ... # seconds
phase_encoding_direction = ... # one of i, j, k, i-, j-, k-, x, y, z, x-, y-, z-
field_maps_native, displacement_maps, field_maps = medic(
phases, magnitudes, TEs, total_readout_time, phase_encoding_direction
)Returns are nibabel.Nifti1Image objects:
field_maps_native— field maps in distorted space (Hz). Mostly useful for debugging.displacement_maps— displacement in undistorted space (mm). Convert withdisplacement_map_to_fieldbefore applying.field_maps— field maps in undistorted space (Hz). Equivalent to topup/fugue output, but framewise.
To convert a displacement map to a per-frame warp field for your tool of choice:
displacement_maps.to_filename("/path/to/save.nii.gz")
displacement_field = displacement_map_to_field(
displacement_maps, axis="y", format="itk", frame=0
)format selects the output convention. Apply with the matching tool:
format |
Apply with | Notes |
|---|---|---|
itk |
warpkit.utilities.resample_image |
warpkit's internal format. |
ants |
antsApplyTransforms |
ANTs uses ITK underneath, but its warp convention differs from ours. |
afni |
3dNwarpApply |
|
fsl |
applywarp |
If you'd rather use fugue, feed it field_maps instead. |
All warpkit CLIs are installed on PATH with a wk- prefix to avoid colliding
with same-named tools from FSL/ANTs/AFNI/etc.:
| Command | Purpose |
|---|---|
wk-medic |
End-to-end MEDIC pipeline: phase + magnitude → field maps + displacement maps. |
wk-unwrap-phase |
Stage 1: ROMEO multi-echo phase unwrapping → unwrapped phase + per-frame masks. |
wk-compute-fieldmap |
Stage 2: take stage-1 outputs → native + displacement + undistorted-space field maps. |
wk-apply-warp |
Resample an image through a displacement map / field (single or per-frame series). |
wk-convert-warp |
Convert between maps ↔ fields and between ITK / FSL / ANTs / AFNI; --invert warps. |
wk-convert-fieldmap |
Convert between mm displacement maps/fields and Hz B0 field maps. |
wk-compute-jacobian |
Per-voxel Jacobian determinant (1 = no change, <1 = compression, >1 = expansion). |
wk-medic runs the full pipeline; wk-unwrap-phase + wk-compute-fieldmap
run the same thing in two stages so you can inspect/reuse the unwrapped
phase. Acquisition parameters can come either from BIDS sidecars or from the
command line — pick one.
From BIDS sidecars:
wk-medic \
--magnitude mag_e1.nii.gz mag_e2.nii.gz mag_e3.nii.gz \
--phase phase_e1.nii.gz phase_e2.nii.gz phase_e3.nii.gz \
--metadata mag_e1.json mag_e2.json mag_e3.json \
--out-prefix sub-01_run-01EchoTime is read per file (seconds → converted to ms internally); TotalReadoutTime and PhaseEncodingDirection are taken from the first sidecar.
Or by passing acquisition parameters directly:
wk-medic \
--magnitude mag_e1.nii.gz mag_e2.nii.gz mag_e3.nii.gz \
--phase phase_e1.nii.gz phase_e2.nii.gz phase_e3.nii.gz \
--TEs 14.2 38.93 63.66 \
--total-readout-time 0.0501 \
--phase-encoding-direction j- \
--out-prefix sub-01_run-01--TEs is in milliseconds, --total-readout-time in seconds, and --phase-encoding-direction is one of i, j, k, i-, j-, k-, x, y, z, x-, y-, z-.
Run any wk-* CLI with --help for the full option list.
Apply a MEDIC displacement-map series to the BOLD it was derived from (per-frame distortion correction):
wk-apply-warp \
--input bold.nii.gz \
--transform sub-01_run-01_displacementmaps.nii \
--phase-encoding-axis j \
--output bold_corrected.nii.gzConvert MEDIC's per-frame displacement maps into per-frame ANTs-format displacement fields:
wk-convert-warp \
--input sub-01_run-01_displacementmaps.nii \
--to field --axis j --to-format ants \
--output field_{0..14}.nii.gzCompute the per-frame Jacobian determinant (volume-change map) of those displacement maps:
wk-compute-jacobian \
--input sub-01_run-01_displacementmaps.nii \
--axis j \
--output sub-01_run-01_jacobian.niiConvert MEDIC's mm displacement maps to a Hz B0 field map (or back — this CLI handles either direction, with maps or fields on the mm side):
wk-convert-fieldmap \
--input sub-01_run-01_displacementmaps.nii \
--to fieldmap \
--total-readout-time 0.0501 \
--phase-encoding-direction j- \
--output sub-01_run-01_fieldmap.niiVahdeta Suljic <suljic@wustl.edu>, Andrew Van <vanandrew77@gmail.com>

