Medical image I/O for Python — read and write NIfTI, DICOM, MetaImage, and more in one consistent API.
- One function reads any format; format auto-detected from path
- Returns a NumPy array + rich
MetaData(affine, orientation, spacing) — no format-specific objects to unwrap - Transparent coordinate system normalization between ITK and NiBabel conventions
- Metadata-only reads (
read_meta) for large files when you only need spatial info
pip install medioimport medio
arr, meta = medio.read_img('scan.nii.gz')
print(meta.ornt, meta.spacing) # e.g. 'LPI', [0.5, 0.5, 1.0]
medio.save_img('out.mhd', arr, meta)meta = medio.read_meta('large_scan.nii.gz')
print(meta.spatial_shape) # (256, 256, 128)
print(meta.affine.spacing) # [0.98, 0.98, 1.5]arr, meta = medio.read_img('scan.nii.gz', desired_ornt='RAS')
# arr axes are reordered; meta.affine updated to matcharr, meta = medio.read_img('scan.mhd')
medio.save_dir('dicom_out/', arr, meta)from medio.medimg import MedImg
mimg = MedImg(arr, meta)
cropped = mimg[2:8, 3:7, :] # origin updated
downsampled = mimg[::2, ::2, ::1] # spacing updated| Format | Extensions | Default backend |
|---|---|---|
| NIfTI | .nii, .nii.gz |
ITK |
| DICOM | directory or .dcm |
ITK |
| MetaImage | .mhd, .mha |
ITK |
| NIfTI (NiBabel) | .nii, .nii.gz |
backend='nib' |
| DICOM (pydicom) | .dcm |
backend='pdcm' |
| Other ITK formats | .png, .jpg, … |
ITK |
medio.read_img(input_path, desired_ornt=None, backend=None, dtype=None,
header=False, channels_axis=-1, coord_sys='itk', **kwargs)
→ tuple[np.ndarray, MetaData]| Parameter | Type | Default | Description |
|---|---|---|---|
input_path |
path-like | — | File or DICOM directory |
desired_ornt |
str | None | None |
Reorient to this axis code (e.g. 'RAS') |
backend |
str | None | None |
Force backend: 'itk', 'nib', 'pdcm' |
dtype |
dtype | None | None |
Cast array to this dtype |
header |
bool | False |
Include raw format header in MetaData.header |
channels_axis |
int | None | -1 |
Axis for multi-channel (e.g. RGB) images |
coord_sys |
'itk' | 'nib' | None |
'itk' |
Coordinate convention for orientation and metadata |
**kwargs are passed to the backend. ITK-specific: pixel_type, fallback_only, series. pydicom-specific: globber, allow_default_affine, series.
medio.read_meta(input_path, desired_ornt=None, backend=None,
header=False, coord_sys='itk', **kwargs)
→ MetaDataSee read_img for parameters. Reads only spatial metadata without loading pixel data.
medio.save_img(filename, np_image, metadata, use_original_ornt=True,
backend=None, dtype=None, channels_axis=None,
mkdir=False, parents=False, **kwargs)| Parameter | Type | Default | Description |
|---|---|---|---|
filename |
path-like | — | Output file path (format inferred from suffix) |
np_image |
ndarray | — | Image array |
metadata |
MetaData | — | Spatial metadata |
use_original_ornt |
bool | True |
Reorient to metadata.orig_ornt before saving |
backend |
str | None | None |
Force backend: 'itk' or 'nib' |
dtype |
dtype | None | None |
Cast before saving |
channels_axis |
int | None | None |
Axis of channel dimension in np_image |
mkdir |
bool | False |
Create the output directory if it doesn't exist |
parents |
bool | False |
Create all missing parent directories |
medio.save_dir(dirname, np_image, metadata, use_original_ornt=True,
dtype=None, channels_axis=None, parents=False,
exist_ok=False, allow_dcm_reorient=False, **kwargs)Saves a 3D array as a DICOM series of 2D slices.
| Parameter | Default | Description |
|---|---|---|
dirname |
— | Output directory |
exist_ok |
False |
Allow writing into an existing non-empty directory |
allow_dcm_reorient |
False |
Reorient to nearest right-handed orientation if needed |
pattern |
'IM{}.dcm' |
Filename pattern; {} is replaced with the slice number |
metadata_dict |
None |
Override or add DICOM tags, e.g. {'0008|0060': 'US'} |
medio.MetaData(affine, coord_sys='itk', orig_ornt=None, header=None, spatial_shape=None)| Property | Type | Description |
|---|---|---|
affine |
Affine |
4×4 spatial transform (index space → physical space) |
coord_sys |
str | 'itk' or 'nib' |
ornt |
str | Current orientation code (e.g. 'LPI'), derived from affine |
orig_ornt |
str | Orientation before any reorientation |
spacing |
ndarray | Voxel spacing — alias for affine.spacing |
header |
dict | None | Raw format header (populated when header=True in read_img) |
spatial_shape |
tuple | None | Image dimensions (populated by read_meta) |
Methods: .convert(dest_coord_sys) — in-place convention switch; .clone() — deep copy.
A 4×4 NumPy array subclass with named spatial accessors.
from medio import Affine
import numpy as np
aff = Affine(np.eye(4))
aff = Affine(direction=np.eye(3), spacing=[0.5, 0.5, 1.0], origin=[0., 0., 0.])
coord = aff.index2coord([4, 0, 9]) # map voxel index → physical coordinateProperties: .spacing, .origin, .direction (all gettable and settable). Method: .clone().
For a mathematical background see NiBabel's affine documentation.
Container for an image array + metadata with spatially-aware indexing.
from medio.medimg.medimg import MedImg
mimg = MedImg(arr, meta) # from array + metadata
mimg = MedImg.from_file('scan.mhd') # load from fileIndexing crops or downsamples the array and updates the affine automatically:
| Indexing | Effect on metadata |
|---|---|
mimg[2:8, 3:7, :] |
origin updated to new start voxel |
mimg[::2, ::2, ::1] |
spacing scaled by step sizes |
mimg[..., 5:15] |
ellipsis supported |
Properties: .np_image, .metadata. Method: .save(filename).
medio uses ITK convention by default (coord_sys='itk').
Pass coord_sys='nib' to read_img / read_meta to work in NiBabel convention throughout.
Apache 2.0 — see LICENSE.
Issues and contributions: github.com/RSIP-Vision/medio/issues