CMPL — CMRR MRI Processing Libraries
PyPI: https://pypi.org/project/cmpl/
GitHub: https://github.com/ehedayati/cmpl
CMPL is a Python package for MRI processing workflows developed at CMRR. It provides tools for MRI reconstruction, quantitative MRI, visualization, DICOM/NIfTI conversion and I/O, and supporting numerical and data utilities.
CMPL is organized as a modular library: the base installation stays lightweight, while larger or domain-specific dependencies are installed only when the corresponding functionality is needed.
Highlights
- Direct, geometry-aware conventional and Enhanced DICOM to NIfTI conversion with JSON metadata sidecars
- Multi-echo DICOM support, including 4D NIfTI output ordered by echo time
- Packaged
cmpl-dicom-to-nifticommand-line converter - DICOM geometry and acquisition-metadata utilities
- 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 CMPL
- Optional pandas-based indexing for CMPL-style medical-data directory structures
- Lazy package imports so
import cmpldoes not eagerly load large optional dependencies - Convenient aliases such as
cmpl.recon,cmpl.qmr,cmpl.vis, andcmpl.io
Requirements
CMPL requires:
- Python >= 3.10
- NumPy >= 1.26, < 3
- SciPy >= 1.13, < 2
- tqdm >= 4.66
Additional dependencies are installed through optional extras.
Installation
Install the lightweight base package:
python -m pip install cmpl
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 |
All optional functionality declared by CMPL |
dev |
Testing, linting, build, and release tools |
Examples:
python -m pip install "cmpl[io]"
python -m pip install "cmpl[viz]"
python -m pip install "cmpl[torch]"
python -m pip install "cmpl[io,data,viz,torch]"
python -m pip install "cmpl[all]"
Quantitative-MRI fitting currently uses both PyTorch and Matplotlib, so for qMRI workflows install:
python -m pip install "cmpl[torch,viz]"
Quick start
import cmpl
print(cmpl.__version__)
CMPL exposes convenient aliases for commonly used subpackages:
cmpl.recon # reconstruction
cmpl.qmr # quantitative MRI
cmpl.vis # visualization
cmpl.io # I/O utilities
cmpl.dicom # DICOM metadata and geometry utilities
cmpl.utils # utilities
The aliases are resolved lazily, so importing CMPL itself does not require every optional dependency to be loaded.
DICOM and NIfTI I/O
Install the I/O extra:
python -m pip install "cmpl[io]"
Convert a DICOM series directly to NIfTI
CMPL includes direct DICOM-series to NIfTI conversion for both conventional and Enhanced DICOM. The converter detects the DICOM representation automatically, preserves spatial geometry, supports single- and multi-echo acquisitions, writes the NIfTI image, and creates a matching JSON sidecar containing acquisition metadata and source geometry.
import cmpl
metadata = cmpl.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, CMPL appends .nii.gz automatically.
For a single echo, the output is a 3D image. When multiple echoes are present, CMPL groups volumes by DICOM EchoTime, orders them by echo time, and writes a 4D NIfTI image.
The JSON sidecar includes:
- selected acquisition metadata
- echo time or echo times in milliseconds
- original DICOM slice-plane geometry in LPS coordinates
- the SimpleITK image size, origin, spacing, and direction used for conversion
The returned value is the same metadata dictionary written to the JSON sidecar.
If a directory contains multiple DICOM series, a specific SeriesInstanceUID can be selected:
metadata = cmpl.io.dicom_to_nifti(
"/path/to/dicom_directory",
"output.nii.gz",
series_id="1.2.840...",
)
Command-line DICOM conversion
Installing the I/O extra also installs the cmpl-dicom-to-nifti command:
python -m pip install "cmpl[io]"
Convert a DICOM series with automatic conventional/Enhanced-DICOM detection:
cmpl-dicom-to-nifti /path/to/dicom_series
The same CLI can also be invoked as a Python module:
python -m cmpl.cli.dicom_to_nifti /path/to/dicom_series
If the output path is omitted, CMPL writes the NIfTI image and JSON sidecar to the current directory using the DICOM directory name:
./<series_directory_name>.nii.gz
./<series_directory_name>.json
An explicit output path can also be supplied:
cmpl-dicom-to-nifti \
/path/to/dicom_series \
/path/to/output.nii.gz
Progress output is enabled by default. Disable it with:
cmpl-dicom-to-nifti /path/to/dicom_series --no-verbose
The same CLI handles conventional single-frame DICOM series and Enhanced multi-frame DICOM series. For multi-echo data, echo volumes are ordered by EchoTime and written as a 4D NIfTI image.
Read a NIfTI file
from cmpl.utilities.io import nifti_read
nifti_image, data = nifti_read("image.nii.gz")
Replace NIfTI data while preserving geometry
from cmpl.utilities.io import update_nifti_data
updated = update_nifti_data(
"reference.nii.gz",
new_data,
output_path="updated.nii.gz",
)
Load a DICOM directory as a NumPy array
from cmpl.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 data arranged as:
x, y, z, echo
depending on the acquisition metadata and requested reshaping behavior.
Read a DICOM series as SimpleITK
from cmpl.utilities.io import dicom_to_SimpleITK
image = dicom_to_SimpleITK("/path/to/dicom_directory")
The returned image is 3D for a single echo and 4D when multiple echoes are detected.
Write a SimpleITK image as NIfTI
from cmpl.utilities.io import itk_to_nifti
output_path = itk_to_nifti(
image,
"output.nii.gz",
)
DICOM geometry and metadata helpers
CMPL separates DICOM geometry and acquisition-metadata handling into dedicated modules under cmpl.dicom.
from cmpl.dicom import (
extract_slice_geometry,
get_slice_position,
)
geometry = extract_slice_geometry("slice001.dcm")
position = get_slice_position("slice001.dcm")
Enhanced-DICOM helpers remain available as well:
from cmpl.dicom.enhanced_dicom import (
get_slice_thickness,
get_spacing_between_slices,
voxel_sizes_detailed,
)
details = voxel_sizes_detailed(dataset)
Reconstruction
Reconstruction functionality is available under:
cmpl.recon
PyTorch is required for the current reconstruction implementations:
python -m pip install "cmpl[torch]"
1D GRAPPA
from cmpl.reconstruction.grappa import grappa_1d_recon
reconstructed_kspace = grappa_1d_recon(
calibration_kspace,
undersampled_kspace,
reduction_factor=2,
kx=3,
ky=3,
)
calibration_kspace and undersampled_kspace are expected to contain coil-resolved k-space data. The current implementation uses the ordering:
frequency, phase, slice, coils
2D GRAPPA
from cmpl.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 cmpl.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.
Quantitative MRI
Quantitative MRI functionality is available under:
cmpl.qmr
Install the PyTorch and visualization dependencies:
python -m pip install "cmpl[torch,viz]"
Reconstruct a multi-echo signal from T2* and S0 maps
import numpy as np
from cmpl.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)
The signal model is:
S(TE) = S0 * exp(-TE / T2*)
Fit a 3D two-parameter T2* model
from cmpl.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"]
If CUDA is available and no device is supplied, the function can select a CUDA device automatically. CUDA usage can significantly accelerate fitting.
Calculate normalized fitting error
from cmpl.quantitative_MRI import calculate_rmse_percentage_s0
rmse_pct, rse_pct = calculate_rmse_percentage_s0(
original_images,
reconstructed_images,
s0_map,
return_numpy=True,
)
CMPL also contains two- and three-parameter 2D/3D T2* fitting functions.
Visualization
Install the visualization extra:
python -m pip install "cmpl[viz]"
Browse or display a 3D MRI volume
from cmpl.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 cmpl.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 so visualization and other numerical workflows do not require unrelated optional dependencies.
from cmpl.utilities.numerical import resize_matrix
resized = resize_matrix(
image,
target_shape=(600, 600),
)
resize_matrix accepts NumPy arrays and PyTorch tensors. PyTorch is imported at runtime only when a Torch tensor is actually passed to the function.
For backward compatibility, older imports such as:
from cmpl.utilities.utils import resize_matrix
continue to work.
Data indexing
Install the data extra:
python -m pip install "cmpl[data]"
CMPL includes a pandas-based utility for indexing a directory tree that follows the CMPL medical-data convention:
from cmpl.utilities.df_build import build_medical_data_frame
df = build_medical_data_frame("/path/to/root")
The utility is designed around a structure such as:
root/
├── Study001/
│ ├── Dicoms/
│ │ └── <contrast>/
│ └── h5_files/
│ └── <contrast>.h5
└── Study002/
└── ...
This utility is convention-specific rather than a general filesystem indexer.
Lazy loading and optional dependencies
CMPL is designed so that unrelated optional packages are not imported simply because the top-level package is imported.
For example:
import cmpl
does not immediately import PyTorch, Matplotlib, pandas, nibabel, pydicom, SimpleITK, h5py, or the Jupyter visualization stack.
Optional functionality is loaded when its corresponding module or function is accessed. This keeps startup lightweight and allows users to install only the dependencies required for their workflow.
Development
Clone the project and install it in editable mode with development dependencies:
python -m pip install -e ".[dev]"
For development across the currently tested major feature groups:
python -m pip install -e ".[dev,io,data,viz,torch]"
Run the test suite:
python -m pytest tests/ -v
The test suite includes:
- lazy-import and dependency-boundary tests
- qMRI numerical tests
- GRAPPA and SENSE reconstruction tests
- visualization smoke tests
- synthetic NIfTI, DICOM, and SimpleITK I/O tests
- conventional and Enhanced multi-echo DICOM-to-NIfTI conversion and JSON-sidecar tests
- DICOM geometry and metadata tests
- data-indexing tests
Build the package
python -m build
python -m twine check dist/*
Package layout
src/cmpl/
├── _version.py
├── cli/
│ └── dicom_to_nifti.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
CMPL 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cmpl-0.2.3.tar.gz.
File metadata
- Download URL: cmpl-0.2.3.tar.gz
- Upload date:
- Size: 63.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c967886a07e103c783cdc4dc037a2b4089d394906b1ef29cfe78605d1eb2597f
|
|
| MD5 |
d16b1d36c8e5a84f6bd84577f16c333e
|
|
| BLAKE2b-256 |
f4ad4ab4ae857cc25bcb14ecaaeb12d3c2a1071c6a487581868eb0b2ae04df86
|
File details
Details for the file cmpl-0.2.3-py3-none-any.whl.
File metadata
- Download URL: cmpl-0.2.3-py3-none-any.whl
- Upload date:
- Size: 59.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80ed7996d9604bd0ecd1229112cf2c182bbf86af9bad8b2b3baa0a312473a8dc
|
|
| MD5 |
0dc6974347802329a93a8aa5ad33b0de
|
|
| BLAKE2b-256 |
118ad18241b83b46dc2d89653d8fbf26f626de6dc0da5ee6b01ffcca924b6605
|