Loaders

The loaders module provides functions for loading and saving medical images and masks in various formats.

Overview

This module handles I/O operations for medical images, supporting common 2D and 3D formats including NIFTI, PNG, TIFF, and DICOM.

Key Features:

  • Automatic format detection

  • 2D and 3D image support

  • Metadata preservation

  • Image and mask validation

  • Compatibility checking

Supported Formats:

  • 3D: NIFTI (.nii, .nii.gz), NRRD (.nrrd), MetaImage (.mha, .mhd)

  • 2D: PNG, TIFF, JPEG, BMP

  • DICOM: Single files or series

Functions

load_image

medtda.loaders.load_image(path)[source]

Load image from file (auto-detects format).

Supports: - 2D formats: PNG, JPG, JPEG, TIFF, PGM - 3D/4D formats: NIfTI (.nii, .nii.gz), NRRD (.nrrd), MHA (.mha), MHD (.mhd)

Parameters:

path (str or Path) – Path to the image file.

Return type:

Tuple[ndarray, dict]

Returns:

  • image_array (numpy.ndarray) – Loaded image as numpy array.

  • metadata (dict) – Dictionary containing image metadata: - ‘spacing’: Pixel/voxel spacing (tuple) - ‘origin’: Image origin coordinates (tuple) - ‘direction’: Direction cosines (tuple or None for 2D) - ‘dtype’: Original data type - ‘format’: File format

Raises:
  • FileNotFoundError – If the file doesn’t exist.

  • ValueError – If the file format is not supported or required library is missing.

Load a medical image from file.

Signature:

def load_image(path: Union[str, Path]) -> Tuple[np.ndarray, dict]

Parameters:

  • path (str or Path) - Path to image file

Returns:

  • image (np.ndarray) - Image array

  • metadata (dict) - Image metadata including:

    • 'spacing' - Voxel spacing (if available)

    • 'origin' - Image origin

    • 'direction' - Image orientation

    • 'dtype' - Original data type

Example:

from medtda.loaders import load_image

# Load 3D NIFTI image
image, metadata = load_image('ct_scan.nii.gz')
print(f"Image shape: {image.shape}")
print(f"Spacing: {metadata.get('spacing')}")

# Load 2D PNG image
image_2d, metadata_2d = load_image('xray.png')

load_mask

medtda.loaders.load_mask(path)[source]

Load mask from file (auto-detects format).

Masks are loaded preserving all label values for multi-label support.

Parameters:

path (str or Path) – Path to the mask file.

Return type:

Tuple[ndarray, dict]

Returns:

  • mask_array (numpy.ndarray) – Loaded mask as numpy array (dtype: uint8) with original label values preserved.

  • metadata (dict) – Dictionary containing mask metadata (same structure as load_image).

Raises:

Notes

Multi-label masks are supported. Use the label parameter in preprocessing and extraction classes to specify which label to work with.

Load a mask (binary or multi-label) from file.

Signature:

def load_mask(path: Union[str, Path]) -> Tuple[np.ndarray, dict]

Parameters:

  • path (str or Path) - Path to mask file

Returns:

  • mask (np.ndarray) - Mask array (integer type)

  • metadata (dict) - Mask metadata

Example:

from medtda.loaders import load_mask

# Binary mask
mask, metadata = load_mask('segmentation.nii.gz')

# Multi-label mask
multi_mask, metadata = load_mask('multi_label.nii.gz')
print(f"Labels present: {np.unique(multi_mask)}")

save_image

medtda.loaders.save_image(image_array, path, metadata=None)[source]

Save image array to file.

Parameters:
  • image_array (numpy.ndarray) – Image array to save.

  • path (str or Path) – Output file path.

  • metadata (dict, optional) – Image metadata (spacing, origin, direction). Only used for 3D/4D formats.

Raises:

ValueError – If the file format is not supported.

Return type:

None

Save an image array to file.

Signature:

def save_image(
    image_array: np.ndarray,
    path: Union[str, Path],
    metadata: Optional[dict] = None
) -> None

Parameters:

  • image_array (np.ndarray) - Image array to save

  • path (str or Path) - Output file path

  • metadata (dict or None) - Optional metadata (spacing, origin, etc.)

Example:

from medtda.loaders import save_image

# Save processed image
save_image(
    processed_image,
    'output.nii.gz',
    metadata={'spacing': (1.0, 1.0, 1.0)}
)

# Save as 2D PNG
save_image(slice_2d, 'slice.png')

Validation Functions

validate_image

medtda.loaders.validate_image(image)[source]

Validate image array.

Parameters:

image (numpy.ndarray) – Image array to validate.

Raises:
  • TypeError – If image is not a numpy array.

  • ValueError – If image has invalid dimensions or contains invalid values.

Return type:

None

Validate an image array.

Signature:

def validate_image(image: np.ndarray) -> None

Raises:

  • ValueError if image is invalid

Example:

from medtda.loaders import validate_image

try:
    validate_image(image_array)
    print("Image is valid")
except ValueError as e:
    print(f"Invalid image: {e}")

validate_mask

medtda.loaders.validate_mask(mask)[source]

Validate mask array.

Parameters:

mask (numpy.ndarray) – Mask array to validate.

Raises:
  • TypeError – If mask is not a numpy array.

  • ValueError – If mask has invalid dimensions or values.

Return type:

None

Validate a mask array.

Signature:

def validate_mask(mask: np.ndarray) -> None

Raises:

  • ValueError if mask is invalid

Example:

from medtda.loaders import validate_mask

validate_mask(mask_array)

validate_compatibility

medtda.loaders.validate_compatibility(image, mask)[source]

Check image-mask compatibility.

Ensures image and mask have the same shape.

Parameters:
Raises:

ValueError – If image and mask shapes don’t match.

Return type:

None

Validate that image and mask are compatible.

Signature:

def validate_compatibility(
    image: np.ndarray,
    mask: np.ndarray
) -> None

Raises:

  • ValueError if image and mask are incompatible

Example:

from medtda.loaders import validate_compatibility

validate_compatibility(image, mask)
# Raises ValueError if shapes don't match

Complete Examples

Example 1: Basic Loading

from medtda.loaders import load_image, load_mask

# Load image and mask
image, img_meta = load_image('data/patient001.nii.gz')
mask, mask_meta = load_mask('data/patient001_mask.nii.gz')

print(f"Image shape: {image.shape}")
print(f"Image spacing: {img_meta.get('spacing')}")
print(f"Mask labels: {np.unique(mask)}")

Example 2: Loading with Validation

from medtda.loaders import (
    load_image,
    load_mask,
    validate_compatibility
)

# Load
image, _ = load_image('scan.nii.gz')
mask, _ = load_mask('mask.nii.gz')

# Validate
try:
    validate_compatibility(image, mask)
    print("Image and mask are compatible")
except ValueError as e:
    print(f"Error: {e}")

Example 3: Processing and Saving

from medtda import Preprocessor
from medtda.loaders import load_image, save_image

# Load
image, metadata = load_image('original.nii.gz')

# Process
preprocessor = Preprocessor(
    normalize=True,
    spacing=(1.0, 1.0, 1.0)
)
processed = preprocessor.preprocess(image)

# Save with metadata
save_image(
    processed,
    'processed.nii.gz',
    metadata={'spacing': (1.0, 1.0, 1.0)}
)

Example 4: Batch Loading

from medtda.loaders import load_image
import glob
from pathlib import Path

# Load all NIFTI files
image_paths = glob.glob('data/*.nii.gz')

images = []
for path in image_paths:
    image, metadata = load_image(path)
    images.append({
        'name': Path(path).stem,
        'array': image,
        'metadata': metadata
    })

print(f"Loaded {len(images)} images")

Example 5: 2D Image Handling

from medtda.loaders import load_image, save_image
import numpy as np

# Load 2D images
xray, metadata = load_image('xray.png')
print(f"2D image shape: {xray.shape}")

# Process
normalized = (xray - xray.min()) / (xray.max() - xray.min())

# Save as different format
save_image(normalized, 'xray_processed.tiff')

Example 6: Multi-Label Mask

from medtda.loaders import load_mask
from medtda.utils import extract_label_from_mask

# Load multi-label mask
multi_mask, metadata = load_mask('organs.nii.gz')

# Check labels
labels = np.unique(multi_mask)
print(f"Available labels: {labels}")
# e.g., [0, 1, 2, 3] for background, liver, kidney, spleen

# Extract single label
liver_mask = extract_label_from_mask(multi_mask, label=1)

Example 7: Metadata Handling

from medtda.loaders import load_image, save_image

# Load with metadata
image, metadata = load_image('scan.nii.gz')

# Inspect metadata
print("Metadata:")
for key, value in metadata.items():
    print(f"  {key}: {value}")

# Modify metadata
metadata['spacing'] = (1.0, 1.0, 1.0)  # Change to isotropic

# Save with modified metadata
save_image(image, 'scan_modified.nii.gz', metadata=metadata)

Supported Formats

3D Formats

NIFTI (.nii, .nii.gz)

  • Most common medical imaging format

  • Supports metadata (spacing, orientation)

  • Recommended for 3D volumes

image, meta = load_image('brain.nii.gz')

NRRD (.nrrd)

  • Nearly Raw Raster Data

  • Good metadata support

image, meta = load_image('volume.nrrd')

MetaImage (.mha, .mhd)

  • ITK format

  • Separate header and data files (.mhd + .raw)

image, meta = load_image('scan.mha')

2D Formats

PNG

  • Lossless compression

  • Good for masks and processed images

image, meta = load_image('slice.png')

TIFF

  • Supports 16-bit grayscale

  • Good for high dynamic range

image, meta = load_image('microscopy.tiff')

JPEG

  • Lossy compression

  • Not recommended for analysis (lossy)

image, meta = load_image('preview.jpg')

DICOM

DICOM (.dcm)

  • Medical imaging standard

  • Rich metadata

  • May require series loading

# Single DICOM file
image, meta = load_image('slice001.dcm')

# Note: For DICOM series, use specialized tools

Format Detection

Automatic Detection

Format is automatically detected from file extension:

# Automatically detects NIFTI
img, _ = load_image('scan.nii.gz')

# Automatically detects PNG
img, _ = load_image('image.png')

Troubleshooting

Common Issues

Issue: Shape mismatch between image and mask

# Check shapes before processing
image, _ = load_image('image.nii.gz')
mask, _ = load_image('mask.nii.gz')

if image.shape != mask.shape:
    print(f"Shape mismatch: {image.shape} vs {mask.shape}")

Issue: Missing metadata

image, metadata = load_image('image.nii.gz')

# Provide default spacing if missing
spacing = metadata.get('spacing', (1.0, 1.0, 1.0))

Issue: Unsupported format

# Check file extension
from pathlib import Path

path = Path('image.xyz')
if path.suffix not in ['.nii', '.nii.gz', '.nrrd', '.png', '.tiff']:
    print(f"Unsupported format: {path.suffix}")

Performance Tips

  1. Use compressed NIFTI:

    .nii.gz files are smaller and load quickly:

    # Prefer this
    img, _ = load_image('scan.nii.gz')
    
  2. Cache loaded images:

    Avoid reloading the same file:

    # Load once
    image, metadata = load_image('large_scan.nii.gz')
    
    # Reuse image array
    result1 = process1(image)
    result2 = process2(image)
    
  3. Validate once:

    Validate at load time, not during processing:

    from medtda.loaders import load_image, validate_image
    
    image, _ = load_image('scan.nii.gz')
    validate_image(image)  # Once only
    

See Also