Skip to main content

MRIForge — MRI Processing Tools for Python

PyPI version Python versions

PyPI: https://pypi.org/project/mriforge/
GitHub: https://github.com/ehedayati/mriforge

MRIForge is a modular Python toolkit for MRI processing workflows. It provides tools for DICOM/NIfTI conversion and I/O, quantitative MRI, MRI reconstruction, visualization, and supporting numerical and data utilities.

The base installation is intentionally lightweight. Larger or domain-specific dependencies are installed only when the corresponding functionality is needed.

Project rename: MRIForge is the continuation of CMPL. Beginning with MRIForge 0.3.0, the PyPI distribution is mriforge and the Python import namespace is mrif.

Highlights

  • Geometry-aware conventional and Enhanced DICOM to NIfTI conversion
  • JSON metadata sidecars with acquisition and source-geometry information
  • Multi-echo DICOM support with 4D NIfTI output ordered by echo time
  • mriforge-dicom-to-nifti command-line converter
  • mriforge-t2star command-line T2* and S0 mapper
  • DICOM geometry and acquisition-metadata utilities
  • NIfTI data replacement while preserving image geometry and metadata
  • Parallel MRI reconstruction with 1D/2D GRAPPA and conjugate-gradient SENSE
  • Quantitative MRI tools for T2* fitting, signal reconstruction, and fitting-error analysis
  • MRI visualization utilities for 2D comparisons and 3D volume browsing
  • Conventional and Enhanced DICOM, NIfTI, HDF5, and SimpleITK utilities
  • Lightweight numerical utilities shared across MRIForge
  • Optional pandas-based indexing for medical-data directory structures
  • Lazy imports so unrelated optional dependencies are not loaded unnecessarily
  • Convenient aliases such as mrif.recon, mrif.qmr, mrif.vis, and mrif.io

Requirements

MRIForge requires:

  • Python >= 3.10
  • NumPy >= 1.26, < 3
  • SciPy >= 1.13, < 2
  • tqdm >= 4.66

Additional functionality is provided through optional dependency groups.

Installation

Install the lightweight base package:

python -m pip install mriforge

Install only the functionality you need:

Extra Purpose
io DICOM, NIfTI, HDF5, and SimpleITK I/O
data pandas-based data indexing
viz Matplotlib and Jupyter visualization
torch PyTorch-based reconstruction and quantitative MRI
all Complete optional MRIForge environment
dev Testing, linting, build, and release tools

Examples:

python -m pip install "mriforge[io]"
python -m pip install "mriforge[torch]"
python -m pip install "mriforge[viz]"
python -m pip install "mriforge[io,torch]"
python -m pip install "mriforge[all]"

For NIfTI-based T2* mapping:

python -m pip install "mriforge[io,torch]"

Matplotlib is only required when plotting is explicitly requested:

python -m pip install "mriforge[viz]"

Quick start

import mrif

print(mrif.__version__)

MRIForge exposes convenient aliases for commonly used subpackages:

mrif.recon   # reconstruction
mrif.qmr     # quantitative MRI
mrif.vis     # visualization
mrif.io      # I/O utilities
mrif.dicom   # DICOM metadata and geometry utilities
mrif.utils   # utilities

These aliases are resolved lazily, so import mrif does not require every optional dependency to be installed or imported.

Migration from CMPL

MRIForge 0.3.0 introduces a new distribution name and Python namespace:

Old PyPI package:    cmpl
New PyPI package:    mriforge

Old Python import:   cmpl
New Python import:   mrif

For example:

# Before
import cmpl
from cmpl.utilities.io import nifti_read

# MRIForge
import mrif
from mrif.utilities.io import nifti_read

CLI commands also use the MRIForge name:

cmpl-dicom-to-nifti  ->  mriforge-dicom-to-nifti
cmpl-t2star           ->  mriforge-t2star

DICOM and NIfTI I/O

Install the I/O extra:

python -m pip install "mriforge[io]"

Convert a DICOM series to NIfTI

MRIForge supports direct conversion of both conventional and Enhanced DICOM series to NIfTI.

The converter:

  • detects the DICOM representation automatically
  • preserves spatial geometry
  • supports single-echo and multi-echo acquisitions
  • writes a NIfTI image
  • writes a matching JSON metadata sidecar
  • orders multi-echo volumes by echo time
import mrif

metadata = mrif.io.dicom_to_nifti(
    "/path/to/dicom_series",
    "output.nii.gz",
)

This creates:

output.nii.gz
output.json

If the output path does not end in .nii or .nii.gz, MRIForge appends .nii.gz.

For a single echo, the output is a 3D image. For a multi-echo acquisition, MRIForge writes a 4D NIfTI with echoes in the last dimension:

x, y, z, echo

The matching JSON sidecar contains acquisition metadata and source-geometry information. For multi-echo data, echo times are stored in milliseconds under:

{
  "Acquisition": {
    "EchoTimes": [2.5, 5.0, 7.5, 10.0],
    "TimeUnit": "ms"
  }
}

If a directory contains multiple DICOM series, select a specific SeriesInstanceUID:

metadata = mrif.io.dicom_to_nifti(
    "/path/to/dicom_directory",
    "output.nii.gz",
    series_id="1.2.840...",
)

Command-line DICOM conversion

The I/O extra installs:

mriforge-dicom-to-nifti

Convert a DICOM series with automatic conventional/Enhanced-DICOM detection:

mriforge-dicom-to-nifti /path/to/dicom_series

The same CLI can be invoked as a Python module:

python -m mrif.cli.dicom_to_nifti /path/to/dicom_series

If the output path is omitted, MRIForge writes the NIfTI and JSON sidecar to the current directory using the DICOM directory name:

./<series_directory_name>.nii.gz
./<series_directory_name>.json

Specify an explicit output path if needed:

mriforge-dicom-to-nifti \
    /path/to/dicom_series \
    /path/to/output.nii.gz

Progress output is enabled by default. Disable it with:

mriforge-dicom-to-nifti /path/to/dicom_series --no-verbose

The same command handles conventional single-frame DICOM and Enhanced multi-frame DICOM.

Read a NIfTI file

from mrif.utilities.io import nifti_read

nifti_image, data = nifti_read("image.nii.gz")

Replace NIfTI data while preserving the reference image

from mrif.utilities.io import update_nifti_data

updated = update_nifti_data(
    "reference.nii.gz",
    new_data,
    output_path="updated.nii.gz",
)

By default, update_nifti_data preserves the reference image geometry, metadata, NIfTI image type, and source data type. The replacement array must have the same shape as the reference image.

A different output dtype can be requested explicitly:

import numpy as np

updated = update_nifti_data(
    "reference.nii.gz",
    new_data,
    output_path="updated.nii.gz",
    dtype=np.float32,
)

For .nii.gz output, the gzip compression level can also be selected:

updated = update_nifti_data(
    "reference.nii.gz",
    new_data,
    output_path="updated.nii.gz",
    compression_level=6,
)

Save a scalar map using reference NIfTI geometry

from mrif.utilities.io import save_scalar_map_like

save_scalar_map_like(
    reference_image,
    scalar_map,
    "map.nii.gz",
)

This is useful for quantitative maps such as T2* and S0 because the spatial geometry of the source NIfTI is preserved.

Load a DICOM directory as a NumPy array

from mrif.utilities.io import load_dicom_scan_from_dir

volume = load_dicom_scan_from_dir(
    "/path/to/dicom_directory",
    reshape=True,
)

For multi-echo data, the loader can return:

x, y, z, echo

depending on the acquisition metadata and requested reshaping behavior.

Read a DICOM series as SimpleITK

from mrif.utilities.io import dicom_to_SimpleITK

image = dicom_to_SimpleITK("/path/to/dicom_directory")

The returned image is 3D for single-echo data and 4D when multiple echoes are detected.

Write a SimpleITK image as NIfTI

from mrif.utilities.io import itk_to_nifti

output_path = itk_to_nifti(
    image,
    "output.nii.gz",
)

DICOM geometry and metadata helpers

MRIForge separates DICOM geometry and acquisition-metadata handling into dedicated modules under mrif.dicom.

from mrif.dicom import (
    extract_slice_geometry,
    get_slice_position,
)

geometry = extract_slice_geometry("slice001.dcm")
position = get_slice_position("slice001.dcm")

Enhanced-DICOM helpers are also available:

from mrif.dicom.enhanced_dicom import (
    get_slice_thickness,
    get_spacing_between_slices,
    voxel_sizes_detailed,
)

details = voxel_sizes_detailed(dataset)

Quantitative MRI

Quantitative MRI functionality is available under:

mrif.qmr

Install PyTorch support:

python -m pip install "mriforge[torch]"

For NIfTI-based quantitative MRI workflows:

python -m pip install "mriforge[io,torch]"

Signal model

The current two-parameter T2* implementation uses the mono-exponential signal model:

S(TE) = S0 * exp(-TE / T2*)

where:

  • S0 is the extrapolated signal at TE = 0
  • T2* is the transverse relaxation time
  • TE and T2* must use the same time unit

MRIForge conventionally uses milliseconds for T2* workflows.

Fit a 3D two-parameter T2* model

from mrif.quantitative_MRI import t2_star_two_parametric_3D

result = t2_star_two_parametric_3D(
    echo_times,
    images,
    num_iterations=1000,
    initial_lr=0.01,
    initial_T2_star=20.0,
    plot_error=False,
    device="cpu",
)

t2_star_map = result["T2_star_map"]
s0_map = result["S0_map"]

The expected image layout is:

x, y, z, echo

If CUDA is available and no device is supplied, the fitter can select CUDA automatically.

Command-line 3D T2* mapping

MRIForge includes a command-line interface for calculating T2* and S0 maps directly from a 4D multi-echo NIfTI file and its JSON metadata sidecar.

Install the required dependencies:

python -m pip install "mriforge[io,torch]"

Given:

multi_echo.nii.gz
multi_echo.json

run:

mriforge-t2star multi_echo.nii.gz

The JSON sidecar is detected automatically when it has the same basename as the NIfTI file.

The CLI reads echo times from:

{
  "Acquisition": {
    "EchoTimes": [2.5, 5.0, 7.5, 10.0],
    "TimeUnit": "ms"
  }
}

The input NIfTI must be 4D:

x, y, z, echo

and the number of entries in EchoTimes must match the number of volumes in the fourth dimension.

The command writes:

multi_echo_T2star.nii.gz
multi_echo_S0.nii.gz

The T2* map is written in milliseconds. The S0 map retains the signal-intensity units of the input data. Output maps preserve the spatial geometry of the source NIfTI.

Specify a different JSON file:

mriforge-t2star multi_echo.nii.gz \
    --json metadata.json

Specify a custom output prefix:

mriforge-t2star multi_echo.nii.gz \
    -o results/subject01

This creates:

results/subject01_T2star.nii.gz
results/subject01_S0.nii.gz

Request CUDA explicitly:

mriforge-t2star multi_echo.nii.gz --device cuda

If no device is specified, MRIForge uses CUDA when available and otherwise uses CPU.

Optimization settings can also be adjusted:

mriforge-t2star multi_echo.nii.gz \
    --device cuda \
    --iterations 10000 \
    --lr 0.01 \
    --initial-t2star 20

If echo times are present but not ordered, the CLI sorts the echo times and their corresponding NIfTI volumes together before fitting.

Reconstruct a multi-echo signal from T2* and S0 maps

import numpy as np

from mrif.quantitative_MRI import reconstruct_images

t2_star = np.full((64, 64, 8), 20.0, dtype=np.float32)
s0 = np.full((64, 64, 8), 100.0, dtype=np.float32)
echo_times = np.array(
    [0.0, 5.0, 10.0, 15.0],
    dtype=np.float32,
)

images = reconstruct_images(
    t2_star,
    s0,
    echo_times,
    device="cpu",
    return_numpy=True,
)

print(images.shape)
# (64, 64, 8, 4)

Calculate normalized fitting error

from mrif.quantitative_MRI import calculate_rmse_percentage_s0

rmse_pct, rse_pct = calculate_rmse_percentage_s0(
    original_images,
    reconstructed_images,
    s0_map,
    return_numpy=True,
)

MRIForge also contains additional 2D/3D T2* fitting functions.

Plotting is optional. Matplotlib is imported only when plotting is requested.


Reconstruction

Reconstruction functionality is available under:

mrif.recon

Install PyTorch support:

python -m pip install "mriforge[torch]"

1D GRAPPA

from mrif.reconstruction.grappa import grappa_1d_recon

reconstructed_kspace = grappa_1d_recon(
    calibration_kspace,
    undersampled_kspace,
    reduction_factor=2,
    kx=3,
    ky=3,
)

The current implementation expects coil-resolved k-space in the order:

frequency, phase, slice, coils

2D GRAPPA

from mrif.reconstruction.grappa import grappa_2d_recon

reconstructed_kspace = grappa_2d_recon(
    calibration_kspace,
    undersampled_kspace,
    kernel_size=(3, 3, 3),
    reduction_factors=(2, 2),
)

Conjugate-gradient SENSE

from mrif.reconstruction.sense.cg import CG_sense_2D

reconstructed_image = CG_sense_2D(
    undersampled_image_space,
    coil_sensitivity,
)

Inputs to the current SENSE implementation are PyTorch tensors.


Visualization

Install the visualization extra:

python -m pip install "mriforge[viz]"

Browse or display a 3D MRI volume

from mrif.visualization import plot_3D_mri

plot_3D_mri(
    volume,
    slice_number=volume.shape[2] // 2,
    alpha=0.5,
    direction="sagittal",
    cmap="gray",
    vmin=0,
    vmax=1,
    dpi=300,
)

If an interactive Matplotlib backend is available, plot_3D_mri can use interactive controls. Otherwise it falls back to static redraw mode.

Compare images side by side

from mrif.visualization import side_by_side_view

side_by_side_view(
    image_a,
    image_b,
    titles=["Reference", "Reconstruction"],
    color_palette="gray",
)

Numerical utilities

Lightweight numerical helpers are kept separate from heavier I/O modules.

from mrif.utilities.numerical import resize_matrix

resized = resize_matrix(
    image,
    target_shape=(600, 600),
)

resize_matrix accepts NumPy arrays and PyTorch tensors. PyTorch is imported only when a Torch tensor is actually passed.

For backward compatibility within the utilities package:

from mrif.utilities.utils import resize_matrix

continues to work.


Data indexing

Install the data extra:

python -m pip install "mriforge[data]"

MRIForge includes a pandas-based utility for indexing directory trees that follow the package's medical-data convention:

from mrif.utilities.df_build import build_medical_data_frame

df = build_medical_data_frame("/path/to/root")

The expected structure is similar to:

root/
├── Study001/
│   ├── Dicoms/
│   │   └── <contrast>/
│   └── h5_files/
│       └── <contrast>.h5
└── Study002/
    └── ...

This utility is convention-specific rather than a general-purpose filesystem indexer.


Lazy loading and optional dependencies

MRIForge is designed so unrelated optional packages are not imported simply because the top-level package is imported.

For example:

import mrif

does not immediately import PyTorch, Matplotlib, pandas, nibabel, pydicom, SimpleITK, h5py, or the Jupyter visualization stack.

Optional functionality is loaded only when the corresponding module or function is accessed.

Within quantitative MRI, Matplotlib is also loaded lazily: non-plotting T2* workflows do not require Matplotlib.


Development

Clone the project and install it in editable mode with development dependencies:

python -m pip install -e ".[dev]"

For development across the main optional feature groups:

python -m pip install -e ".[dev,io,data,viz,torch]"

Run the full test suite:

python -m pytest tests/ -v

The test suite covers:

  • lazy-import and dependency-boundary behavior
  • qMRI numerical fitting
  • T2* CLI validation and NIfTI output
  • GRAPPA and SENSE reconstruction
  • visualization smoke tests
  • synthetic NIfTI, DICOM, and SimpleITK I/O
  • conventional and Enhanced multi-echo DICOM-to-NIfTI conversion
  • JSON sidecar generation
  • DICOM geometry and metadata
  • data indexing

Build the package

Clean previous build artifacts and build the distributions:

rm -rf build dist *.egg-info src/*.egg-info
python -m build

Validate them:

python -m twine check dist/*

Before publishing, install the built wheel into a clean environment and verify the packaged CLI commands:

mriforge-dicom-to-nifti --help
mriforge-t2star --help

Package layout

src/mrif/
├── _version.py
├── cli/
│   ├── __init__.py
│   ├── dicom_to_nifti.py
│   └── t2star.py
├── dicom/
│   ├── enhanced_dicom.py
│   ├── geometry.py
│   └── metadata.py
├── quantitative_MRI/
│   └── mapping.py
├── reconstruction/
│   ├── grappa/
│   │   ├── grappa_1D.py
│   │   ├── grappa_2D.py
│   │   └── utils.py
│   └── sense/
│       └── cg.py
├── utilities/
│   ├── df_build.py
│   ├── io.py
│   ├── numerical.py
│   └── utils.py
└── visualization/
    └── visualization.py

License

See the LICENSE file included with the project for licensing terms.

Author

MRIForge is developed by Eisa Hedayati at CMRR.

Download files

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

Source Distribution

mriforge-0.3.0.tar.gz (71.1 kB view details)

Uploaded Source

Built Distribution

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

mriforge-0.3.0-py3-none-any.whl (64.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: mriforge-0.3.0.tar.gz
  • Upload date:
  • Size: 71.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for mriforge-0.3.0.tar.gz
Algorithm Hash digest
SHA256 a6f5065c061d90e6774142749be5de6d2890812e6c62d0b71244be45d4eededa
MD5 d3abdc3f6b0d418ae8be0c201692367a
BLAKE2b-256 c64c669a34780dba370013a5a7f81a3cd7a232baf6f7a46213358a098e865f53

See more details on using hashes here.

File details

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

File metadata

  • Download URL: mriforge-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 64.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for mriforge-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7829c52ca8b7f737ec2e41f643cc27431582e7399167fd658c3a8051c7e1a1f8
MD5 ec6cc07696cae04682a45359abb5d7a4
BLAKE2b-256 0fe2c9125b665c5c02d9468881bdddad74668d747555767295459dcf2afcf6b8

See more details on using hashes here.

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