Preprocessor

The Preprocessor class handles image preprocessing operations including normalization, resampling, windowing, and masking.

Overview

The Preprocessor class provides a unified interface for all preprocessing operations on medical images. It’s used internally by FeatureExtractor but can also be used standalone for more control.

Key Features:

  • Intensity normalization (minmax, z-score, robust)

  • Image resampling to target spacing

  • CT windowing

  • ROI cropping with configurable padding

  • Multi-label mask handling

  • Background detection and masking

Basic Usage

Default Preprocessing

from medtda import Preprocessor

preprocessor = Preprocessor(normalize=True)

processed_image, metadata = preprocessor.preprocess(image_array)

With Mask and ROI Cropping

preprocessor = Preprocessor(
    normalize=True,
    normalize_method='robust',
    crop_to_roi=True,
    roi_padding=5
)

processed_image, metadata = preprocessor.preprocess(
    image=image_array,
    mask=mask_array
)

CT Image with Windowing

# CT abdominal scan with soft tissue window
preprocessor = Preprocessor(
    window=(40, 400),  # (center, width)
    normalize=True,
    spacing=(1.0, 1.0, 1.0)
)

processed_image, metadata = preprocessor.preprocess(ct_image)

Class Documentation

class medtda.Preprocessor(spacing=None, window=None, normalize=False, normalize_method='minmax', clip_percentiles=None, background_value=None, label=1, crop_to_roi=True, roi_padding=1)[source]

Bases: object

Standalone image preprocessor for inspection and validation.

Handles traditional image preprocessing: resampling, windowing, normalization, and background masking. Does NOT handle filtration-specific transformations (e.g., negation for superlevel).

Parameters:
  • spacing (tuple or None, default=None) – Target voxel spacing for resampling (3D/4D only). If None, no resampling is performed.

  • window (tuple or None, default=None) – Windowing parameters as (center, width). If None, no windowing is applied.

  • normalize (bool, default=False) – Whether to apply normalization.

  • normalize_method ({'minmax', 'zscore', 'robust'}, default='minmax') – Normalization method (only used if normalize=True): - ‘minmax’: Scales to [0, 1] range - ‘zscore’: Z-score normalization (mean=0, std=1) - ‘robust’: Robust scaling using quantiles

  • clip_percentiles (tuple of float, optional) – If provided, clip intensities to (lower, upper) percentiles before normalization. For example, (1, 99) removes extreme outliers. Only used if normalize=True.

  • background_value (float or None, default=None) – Value to assign to background pixels when a mask is provided. If None, automatically determined: - If normalize=True: -1 (below [0,1] range) - If normalize=False and 2D: 0 - If normalize=False and 3D/4D: -3000

  • label (int or None, default=1) – For multi-label masks, which label value to consider as foreground. If None, treat mask as binary (any non-zero value is foreground).

  • crop_to_roi (bool, default=True) – If True and a mask is provided, crop image and mask to the bounding box of the ROI with padding. This reduces memory usage and speeds up persistent homology computation.

  • roi_padding (int, default=1) – Number of background pixels to include on all sides of the ROI when crop_to_roi is enabled. This ensures the ROI is not cut too tightly.

Examples

Basic preprocessing with normalization:

>>> from medtda import Preprocessor
>>> preprocessor = Preprocessor(
...     normalize=True,
...     normalize_method='minmax',
...     background_value=None
... )
>>> preprocessed_img, metadata = preprocessor.preprocess(
...     image='path/to/image.nii.gz',
...     mask='path/to/mask.nii.gz'
... )
>>> print(metadata['transforms'])
['normalize_minmax', 'background_set']

Preprocessing with resampling to isotropic spacing:

>>> preprocessor = Preprocessor(
...     spacing=(1.0, 1.0, 1.0),  # Resample to 1mm isotropic
...     normalize=True,
...     normalize_method='minmax',
...     crop_to_roi=True
... )
>>> preprocessed_img, metadata = preprocessor.preprocess(
...     image='path/to/ct_scan.nii.gz',
...     mask='path/to/roi_mask.nii.gz'
... )
>>> print(metadata['transforms'])
['resample_1.0x1.0x1.0', 'crop_to_roi_pad1', 'normalize_minmax', 'background_set']
__init__(spacing=None, window=None, normalize=False, normalize_method='minmax', clip_percentiles=None, background_value=None, label=1, crop_to_roi=True, roi_padding=1)[source]

Initialize preprocessor with parameters.

set_spacing(spacing)[source]

Update spacing parameter.

Parameters:

spacing (tuple or None) – Target voxel spacing for resampling.

Return type:

None

set_window(window_center, window_width)[source]

Set windowing parameters.

Parameters:
  • window_center (float) – Window center value.

  • window_width (float) – Window width value.

Return type:

None

set_normalize(enabled, method='minmax')[source]

Enable/disable normalization and set method.

Parameters:
  • enabled (bool) – Whether to enable normalization.

  • method ({'minmax', 'zscore', 'robust'}, default='minmax') – Normalization method.

Return type:

None

set_clip_percentiles(percentiles)[source]

Set percentile clipping for outlier removal.

Parameters:

percentiles (tuple of float or None) – If provided, should be (lower_percentile, upper_percentile) where 0 <= lower_percentile < upper_percentile <= 100. Values outside these percentiles will be clipped. Set to None to disable clipping.

Return type:

None

set_background_value(value)[source]

Set background value for masked regions.

Parameters:

value (float or None) – Background value, or None for automatic determination.

Return type:

None

set_label(label)[source]

Set label value to extract from multi-label mask.

Parameters:

label (int or None) – Label value to extract. If None, treat mask as binary.

Return type:

None

preprocess(image, mask=None, label=<object object>)[source]

Main preprocessing method.

Parameters:
  • image (str, Path, or numpy.ndarray) – Input image (file path or array).

  • mask (str, Path, or numpy.ndarray, optional) – Input mask (file path or array).

  • label (int or None, optional) – Label value to extract from mask. If None, uses instance default.

Return type:

Tuple[ndarray, Dict]

Returns:

  • preprocessed_image (numpy.ndarray) – Preprocessed image ready for PH computation.

  • metadata (dict) – Dictionary containing:

    • ’original_range’: (min, max) of original image

    • ’final_range’: (min, max) of preprocessed image

    • ’transforms’: list of applied transformations

    • ’background_value’: actual background value used

    • ’original_shape’: shape of original image

    • ’final_shape’: shape after preprocessing

    • ’label’: label value used for mask extraction

    • ’crop_info’: dict with cropping details (None if not cropped)

      • ’bbox’: tuple of slices defining the bounding box

      • ’original_shape’: original image shape

      • ’cropped_shape’: shape after cropping

      • ’roi_size’: number of voxels in ROI

      • ’reduction_factor’: ratio of cropped size to original size

preprocess_and_save(image, mask=None, label=<object object>, output_path=None)[source]

Preprocess and save result to disk.

Useful for inspection and debugging.

Parameters:
  • image (str, Path, or numpy.ndarray) – Input image.

  • mask (str, Path, or numpy.ndarray, optional) – Input mask.

  • label (int or None, optional) – Label value to extract from mask. If None, uses instance default.

  • output_path (str or Path, optional) – Path to save preprocessed image. If None, uses ‘preprocessed_{original_name}’.

Return type:

Tuple[ndarray, Dict]

Returns:

  • preprocessed_image (numpy.ndarray) – Preprocessed image.

  • metadata (dict) – Preprocessing metadata.

get_preprocessing_info()[source]

Return dictionary of current preprocessing settings.

Returns:

Dictionary with current parameter values.

Return type:

dict

Constructor Parameters

Parameter

Type

Description

spacing

tuple or None

Target voxel spacing for resampling (e.g., (1.0, 1.0, 1.0) for isotropic 1mm)

window

tuple or None

CT windowing as (center, width)

normalize

bool

Enable intensity normalization (default: False)

normalize_method

str

Normalization method: 'minmax', 'zscore', or 'robust' (default: 'minmax')

clip_percentiles

tuple or None

Clip intensities to (lower, upper) percentiles before normalization (default: None)

background_value

float or None

Background pixel value (auto-detected if None)

label

int or None

Extract specific label from multi-label mask (default: 1)

crop_to_roi

bool

Crop to ROI bounding box (default: True)

roi_padding

int

Padding around ROI in pixels (default: 1)

Methods

preprocess

Preprocessor.preprocess(image, mask=None, label=<object object>)[source]

Main preprocessing method.

Parameters:
  • image (str, Path, or numpy.ndarray) – Input image (file path or array).

  • mask (str, Path, or numpy.ndarray, optional) – Input mask (file path or array).

  • label (int or None, optional) – Label value to extract from mask. If None, uses instance default.

Return type:

Tuple[ndarray, Dict]

Returns:

  • preprocessed_image (numpy.ndarray) – Preprocessed image ready for PH computation.

  • metadata (dict) – Dictionary containing:

    • ’original_range’: (min, max) of original image

    • ’final_range’: (min, max) of preprocessed image

    • ’transforms’: list of applied transformations

    • ’background_value’: actual background value used

    • ’original_shape’: shape of original image

    • ’final_shape’: shape after preprocessing

    • ’label’: label value used for mask extraction

    • ’crop_info’: dict with cropping details (None if not cropped)

      • ’bbox’: tuple of slices defining the bounding box

      • ’original_shape’: original image shape

      • ’cropped_shape’: shape after cropping

      • ’roi_size’: number of voxels in ROI

      • ’reduction_factor’: ratio of cropped size to original size

Main preprocessing method that applies all configured operations.

Signature:

def preprocess(
    self,
    image: Union[str, Path, np.ndarray],
    mask: Optional[Union[str, Path, np.ndarray]] = None
) -> Tuple[np.ndarray, Dict]

Parameters:

  • image (str, Path, or np.ndarray) - Input image (file path or array)

  • mask (str, Path, np.ndarray, or None) - Optional binary or multi-label mask

Returns:

  • preprocessed_image (np.ndarray) - Preprocessed image

  • metadata (dict) - Dictionary with keys: 'original_range', 'final_range', 'transforms', 'background_value', 'original_shape', 'final_shape', 'label', 'crop_info'

Processing Order:

  1. Resampling (if spacing is set)

  2. ROI cropping (if crop_to_roi=True and mask provided)

  3. Windowing (if window is set)

  4. Normalization (if normalize=True)

  5. Background masking (if mask provided)

Example:

preprocessor = Preprocessor(
    spacing=(1.0, 1.0, 1.0),
    normalize=True,
    crop_to_roi=True
)

processed, metadata = preprocessor.preprocess(image, mask)

Normalization Methods

minmax

Scales intensities to [0, 1] range:

preprocessor = Preprocessor(normalize_method='minmax')

Formula: (x - min) / (max - min)

zscore

Z-score normalization (mean=0, std=1):

preprocessor = Preprocessor(normalize_method='zscore')

Formula: (x - mean) / std

robust

Robust normalization using percentiles:

preprocessor = Preprocessor(normalize_method='robust')

Formula: (x - median) / IQR where IQR is the interquartile range (75th - 25th percentile)

Windowing

CT Windowing for Different Tissues

# Soft tissue window
preprocessor_soft = Preprocessor(window=(40, 400))

# Lung window
preprocessor_lung = Preprocessor(window=(-600, 1500))

# Bone window
preprocessor_bone = Preprocessor(window=(300, 1500))

# Brain window
preprocessor_brain = Preprocessor(window=(40, 80))

Window values are specified as (center, width).

ROI Cropping

Crop to Bounding Box with Padding

preprocessor = Preprocessor(
    crop_to_roi=True,
    roi_padding=10  # 10 pixels padding on all sides
)

# Crops to ROI bounding box with 10-pixel border
cropped = preprocessor.preprocess(image, mask)

Multi-Label Mask Handling

Extract Specific Label

# Multi-label mask: 0=background, 1=liver, 2=tumor
preprocessor = Preprocessor(
    label=2,  # Extract tumor only
    crop_to_roi=True
)

# Only processes the tumor region
tumor_region = preprocessor.preprocess(image, multi_label_mask)

Complete Example

Comprehensive Preprocessing Pipeline

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

# Load data
image, img_metadata = load_image('ct_scan.nii.gz')
mask, mask_metadata = load_mask('liver_mask.nii.gz')

# Configure preprocessor
preprocessor = Preprocessor(
    # Resample to isotropic 1mm spacing
    spacing=(1.0, 1.0, 1.0),

    # Apply soft tissue window (CT)
    window=(40, 400),

    # Robust normalization (handles artifacts well)
    normalize=True,
    normalize_method='robust',

    # Crop to liver ROI with padding
    crop_to_roi=True,
    roi_padding=5
)

# Preprocess
processed_image, metadata = preprocessor.preprocess(image, mask)

print(f"Original shape: {image.shape}")
print(f"Processed shape: {processed_image.shape}")
print(f"Value range: [{processed_image.min():.3f}, {processed_image.max():.3f}]")

Step-by-Step Preprocessing

For manual step-by-step control, individual preprocessing functions from the utils module can be used:

from medtda.utils import (
    resample_image,
    normalize_image,
    crop_to_roi,
    extract_label_from_mask
)

# Step 1: Resample
resampled = resample_image(
    image,
    original_spacing=(1.5, 1.5, 3.0),
    target_spacing=(1.0, 1.0, 1.0)
)

# Step 2: Extract label from mask
binary_mask = extract_label_from_mask(multi_label_mask, label=2)

# Step 3: Crop to ROI
cropped_image, cropped_mask = crop_to_roi(
    resampled,
    binary_mask,
    padding=5
)

# Step 4: Normalize
normalized = normalize_image(
    cropped_image,
    method='robust',
    mask=cropped_mask
)

Common Patterns

Pattern 1: Minimal Preprocessing

Just normalization:

preprocessor = Preprocessor(normalize=True)
processed = preprocessor.preprocess(image)

Pattern 2: CT Preprocessing

Resampling + windowing + normalization:

preprocessor = Preprocessor(
    spacing=(1.0, 1.0, 1.0),
    window=(40, 400),
    normalize=True
)
processed = preprocessor.preprocess(ct_image)

Pattern 3: ROI-Focused Analysis

Extract and crop to specific region:

preprocessor = Preprocessor(
    label=2,  # Extract tumor
    crop_to_roi=True,
    roi_padding=10,
    normalize=True,
    normalize_method='robust'
)
processed = preprocessor.preprocess(image, multi_label_mask)

Pattern 4: No Preprocessing

Use raw image values:

preprocessor = Preprocessor(normalize=False)
processed = preprocessor.preprocess(image)
# Returns image unchanged (just validates it)

See Also