Bits & Flames bitsandflames/fyron

BOA Radiomics

fyron.boa_radiomics extracts PyRadiomics features from BOA cohort folders. It is designed for cases where BOA has already produced CT images and segmentation masks such as body-regions.nii.gz or total.nii.gz, and you want model-ready radiomics features per patient.

For the combined BOA workflow overview, see BOA. For JSON measurement features, see BOA Extraction. For visual quality-control collages, see BOA Visualization.

Install

bash
uv add "fyron[radiomics]"

This installs PyRadiomics. Fyron's imaging stack already uses SimpleITK.

Expected Folder Layout

text
boa-cohort/
  patient0001/
    ct.nii.gz
    body-regions.nii.gz
    total.nii.gz
  patient0002/
    image.nii.gz
    body-regions.nii.gz
    total.nii.gz

The default CT lookup tries several common names:

text
ct.nii.gz
CT.nii.gz
image.nii.gz
CT/image.nii.gz
ct.nii
image.nii

You can pass your own image_filename if your BOA export uses a different layout.

Imports

python
from fyron.boa_radiomics import (
    discover_boa_radiomics_cases,
    extract_case_radiomics_features,
    extract_boa_radiomics_features,
)

Function Parameter Reference

discover_boa_radiomics_cases

ParameterRequiredDefaultDescription
cohort_folderyesnoneRoot folder containing BOA patient folders.
segmentation_filenameno"total.nii.gz"Segmentation file used to identify completed cases.

Returns a sorted list of patient folders.

extract_case_radiomics_features

ParameterRequiredDefaultDescription
case_folderyesnonePatient folder containing CT and segmentation files.
image_filenamenocommon CT candidatesCT image filename, path, or fallback sequence.
segmentation_kindno"total""total" or "body_regions".
segmentation_filenamenobased on kindExplicit segmentation filename.
labelsnodefault labelsMapping of label name to integer label value, or a sequence of label integers.
extractornoNonePreconfigured PyRadiomics extractor.
extractor_settingsnoNoneKeyword settings passed to RadiomicsFeatureExtractor.
feature_prefixno"radiomics"Prefix used for output columns.
download_idnofolder nameExplicit case identifier.
include_pathsnoTrueInclude image and segmentation paths in the output row.
exclude_diagnosticsnoTrueDrop PyRadiomics diagnostic metadata columns.
minimum_voxelsno1Skip labels with fewer voxels.
resample_masknoTrueResample segmentation to the CT grid when geometry differs.
on_errorno"skip""skip" or "raise".

Returns one wide feature dictionary or None when required inputs are missing.

extract_boa_radiomics_features

ParameterRequiredDefaultDescription
cohort_folder_or_casesyesnoneCohort root, one case folder, or a list of case folders.
image_filenamenocommon CT candidatesCT image filename or fallback sequence.
segmentation_kindno"total""total" or "body_regions".
segmentation_filenamenobased on kindExplicit segmentation filename.
labelsnodefault labelsLabel mapping or sequence.
extractor_settingsnoNonePyRadiomics settings.
feature_prefixno"radiomics"Prefix used for output columns.
include_pathsnoTrueInclude source paths.
minimum_voxelsno1Skip tiny/empty labels.
num_workersno1Number of multiprocessing workers.
show_progressnoTrueShow tqdm progress.

Returns a pandas.DataFrame with one row per download_id.

CLI Workflow

Use the CLI when radiomics extraction should run as a batch job.

bash
fyron boa-radiomics \
  --cohort-folder /data/boa-cohort \
  --segmentation total \
  --output boa_total_radiomics.csv \
  --num-workers 8

For body-region radiomics:

bash
fyron boa-radiomics \
  --cohort-folder /data/boa-cohort \
  --segmentation body_regions \
  --output boa_body_region_radiomics.csv

Extract Total-Segmentation Radiomics

Use total segmentation radiomics when you want organ-level texture and shape features from total.nii.gz.

python
from fyron.boa_radiomics import extract_boa_radiomics_features

features = extract_boa_radiomics_features(
    cohort_folder_or_cases="/data/boa-cohort",
    segmentation_kind="total",
    segmentation_filename="total.nii.gz",
    image_filename=("ct.nii.gz", "image.nii.gz", "CT/image.nii.gz"),
    labels={
        "liver": 5,
        "spleen": 1,
        "pancreas": 10,
    },
    extractor_settings={
        "binWidth": 25,
        "resampledPixelSpacing": [1, 1, 1],
    },
    num_workers=8,
)

features.to_csv("boa_total_radiomics.csv", index=False)

Output columns follow this pattern:

text
radiomics_total_liver_original_firstorder_Mean
radiomics_total_liver_original_glcm_Contrast
radiomics_total_liver_original_shape_VoxelVolume

Extract Body-Region Radiomics

Use body-region radiomics when you want features from regions in body-regions.nii.gz, such as thorax, abdomen, or pelvis.

python
features = extract_boa_radiomics_features(
    cohort_folder_or_cases="/data/boa-cohort",
    segmentation_kind="body_regions",
    segmentation_filename="body-regions.nii.gz",
    labels={
        "thorax": 3,
        "abdomen": 4,
        "pelvis": 5,
    },
    num_workers=8,
)

If your BOA label map differs, pass your own labels mapping.

Extract One Patient For Validation

Always validate a single patient before launching a full cohort job.

python
from fyron.boa_radiomics import extract_case_radiomics_features

row = extract_case_radiomics_features(
    case_folder="/data/boa-cohort/patient0001",
    segmentation_kind="total",
    labels={"liver": 5},
    include_paths=True,
    on_error="raise",
)

sorted(row.keys())[:10]

Check the voxel count and a few features against the mask before scaling:

python
row["radiomics_total_liver_voxel_count"]
row["radiomics_total_liver_original_firstorder_Mean"]

Custom PyRadiomics Extractor

For full control, create a PyRadiomics extractor yourself and pass it to the single-case helper.

python
from radiomics import featureextractor
from fyron.boa_radiomics import extract_case_radiomics_features

extractor = featureextractor.RadiomicsFeatureExtractor(
    binWidth=25,
    resampledPixelSpacing=[1, 1, 1],
    correctMask=False,
)
extractor.disableAllFeatures()
extractor.enableFeatureClassByName("firstorder")
extractor.enableFeatureClassByName("shape")

row = extract_case_radiomics_features(
    case_folder="/data/boa-cohort/patient0001",
    segmentation_kind="total",
    labels={"liver": 5},
    extractor=extractor,
)

For multiprocessing, prefer extractor_settings instead of passing an extractor object. Each worker can then construct its own extractor.

Join With BOA Measurements

Radiomics features can be merged with the measurement features from fyron.boa_extraction.

python
from fyron.boa_extraction import extract_boa_features
from fyron.boa_radiomics import extract_boa_radiomics_features

measurements = extract_boa_features(
    cohort_folder_or_cases="/data/boa-cohort",
    num_workers=8,
)

radiomics = extract_boa_radiomics_features(
    cohort_folder_or_cases="/data/boa-cohort",
    segmentation_kind="total",
    labels={"liver": 5, "spleen": 1},
    num_workers=8,
)

features = measurements.merge(
    radiomics,
    on="download_id",
    how="left",
)

Practical Guidance

  • Start with one label and one patient.
  • Keep include_paths=True while validating so every row can be traced back to image and mask files.
  • Check radiomics_<kind>_<label>_voxel_count before trusting texture features.
  • Use minimum_voxels to skip tiny masks.
  • Keep PyRadiomics settings versioned with your analysis.
  • Use the same CT preprocessing and resampling choices for every cohort.
  • Treat body-region label values as project-specific unless your BOA export defines them explicitly.