Python batch workflows#

Use zrad.batch to process datasets organized as described in Expected data structure. Each class writes results to disk:

  • BatchPreprocessor writes images and masks into case subfolders.

  • BatchFilter writes filtered images into case subfolders.

  • BatchRadiomicsExtractor writes one radiomics.csv file.

For individual images or ROIs, use Python image workflows instead. The examples below are independent recipes; replace the paths and filenames with those for your dataset.

Batch preprocessing#

DICOM example:

from zrad.batch import BatchPreprocessor

result = BatchPreprocessor(
    input_directory="path/to/dicom_cases",
    output_directory="path/to/preprocessed_cases",
    input_data_type="dicom",
    modality="CT",
    number_of_threads=8,
    structures=["CTV", "liver"],
    resample_resolution=1.0,
    resample_dimension="3D",
    image_interpolation_method="linear",
    mask_interpolation_method="linear",
    mask_interpolation_threshold=0.5,
).run()

print(result.processed_count, result.failed_count)
for case in result.errors:
    print(case.case_name, case.error)

NIfTI example:

from zrad.batch import BatchPreprocessor

result = BatchPreprocessor(
    input_directory="path/to/nifti_cases",
    output_directory="path/to/preprocessed_cases",
    input_data_type="nifti",
    modality="CT",
    nifti_image_name="imageCT",
    structures=["CTV", "liver"],
    resample_resolution=1.0,
    resample_dimension="2D",
    image_interpolation_method="linear",
    mask_interpolation_method="NN",
).run()

See Resampling guidelines for help choosing resolution, dimension, and image and mask interpolation settings for either example.

Batch filtering#

from zrad.batch import BatchFilter

result = BatchFilter(
    input_directory="path/to/preprocessed_cases",
    output_directory="path/to/filtered_cases",
    input_data_type="nifti",
    modality="CT",
    nifti_image_name="image",
    number_of_threads=8,
    filter_type="Mean",
    filter_dimension="3D",
    padding_type="reflect",
    mean_support=3,
).run()

print(result.processed_count, result.failed_count)

Batch radiomics#

from zrad.batch import BatchRadiomicsExtractor

result = BatchRadiomicsExtractor(
    input_directory="path/to/preprocessed_cases",
    output_directory="path/to/radiomics_output",
    input_data_type="nifti",
    modality="CT",
    nifti_image_name="image",
    structures=["CTV", "liver"],
    number_of_threads=8,
    aggregation_dimension="3D",
    aggregation_method="MERG",
    discretization_method="Number of Bins",
    number_of_bins=64,
).run()

print(result.processed_count, result.skipped_count, result.failed_count)
for case in result.errors:
    print(case.case_name, case.error)

IVH preparation is automatic and independent of texture discretization. See IVH-specific discretization for defaults, Python overrides, and range behavior.

Inspect the result#

All three workflows return BatchResult. Counts describe cases, while result.errors contains case results with an error message:

print(result.processed_count, result.skipped_count, result.failed_count)
for case in result.errors:
    print(case.case_name, case.error)

Preprocessing and radiomics also report individual skipped structures. Inspect these even when failed_count is zero:

# Use with BatchPreprocessor or BatchRadiomicsExtractor results.
for case in result.case_results:
    if case.skipped_structures:
        print(case.case_name, "Skipped structures:", case.skipped_structures)

A radiomics case is counted as processed if at least one structure produces features. Another structure in that case can be skipped without a case-level error. IVH omissions are reported separately, including for processed cases:

for case in result.case_results:
    for structure, reason in case.omitted_ivh_structures.items():
        print(case.case_name, structure, reason)

These cases also appear in result.errors. Check the requested case/mask pairs against the CSV; see Understanding results for metadata and feature-name explanations.

Preprocessing saves each image as image.nii.gz and each mask under its structure name. Use those names when configuring the next step. Filtering saves only the filtered image; if extracting features from it, place it beside the original image and masks in each extraction case folder and set nifti_filtered_image_name to its filename without the extension.

See Batch for all parameters and result fields.