Skip to content

Enums & Config

Enumerations and the inference-configuration model used throughout SPINEPS.

spineps.seg_enums

spineps.seg_enums

Enumerations describing image modalities, acquisitions, model types and pipeline phases used across SPINEPS.

MetaEnum

Bases: EnumMeta

Enum metaclass enabling item in EnumClass membership tests by member name.

Source code in spineps/seg_enums.py
class MetaEnum(EnumMeta):
    """Enum metaclass enabling ``item in EnumClass`` membership tests by member name."""

    def __contains__(cls, item: object) -> bool:
        """Return whether ``item`` names a member of the enum.

        Args:
            item: Candidate member name to test for membership.

        Returns:
            bool: True if ``item`` is a valid member name of the enum, False otherwise.
        """
        try:
            cls[item]
        except (KeyError, ValueError):
            return False
        return True

__contains__

__contains__(item: object) -> bool

Return whether item names a member of the enum.

Parameters:

Name Type Description Default
item object

Candidate member name to test for membership.

required

Returns:

Name Type Description
bool bool

True if item is a valid member name of the enum, False otherwise.

Source code in spineps/seg_enums.py
def __contains__(cls, item: object) -> bool:
    """Return whether ``item`` names a member of the enum.

    Args:
        item: Candidate member name to test for membership.

    Returns:
        bool: True if ``item`` is a valid member name of the enum, False otherwise.
    """
    try:
        cls[item]
    except (KeyError, ValueError):
        return False
    return True

Enum_Compare

Bases: Enum

Base enum that compares equal to other enums by name/value and to plain strings by name.

Provides string-friendly equality, hashing and representation so members can be compared against and interchanged with their string names throughout the pipeline.

Source code in spineps/seg_enums.py
class Enum_Compare(Enum, metaclass=MetaEnum):
    """Base enum that compares equal to other enums by name/value and to plain strings by name.

    Provides string-friendly equality, hashing and representation so members can be compared
    against and interchanged with their string names throughout the pipeline.
    """

    def __eq__(self, __value: object) -> bool:  # noqa: PYI063
        """Compare this member against another enum or a string.

        Args:
            __value (object): Another enum member or a string holding a member name.

        Returns:
            bool: True if the other enum matches by name and value, or the string matches this member's name.
        """
        if isinstance(__value, Enum):
            return self.name == __value.name and self.value == __value.value
        elif isinstance(__value, str):
            return self.name == __value
        else:
            return False

    def __str__(self) -> str:
        """Return the member as ``ClassName.MEMBER``.

        Returns:
            str: Human-readable identifier of the member.
        """
        return f"{type(self).__name__}.{self.name}"

    def __repr__(self) -> str:
        """Return the same string as :meth:`__str__`.

        Returns:
            str: Human-readable identifier of the member.
        """
        return str(self)

    def __hash__(self) -> int:
        """Return the member's integer value as its hash.

        Returns:
            int: The member's value, used for hashing.
        """
        return self.value

__eq__

__eq__(__value: object) -> bool

Compare this member against another enum or a string.

Parameters:

Name Type Description Default
__value object

Another enum member or a string holding a member name.

required

Returns:

Name Type Description
bool bool

True if the other enum matches by name and value, or the string matches this member's name.

Source code in spineps/seg_enums.py
def __eq__(self, __value: object) -> bool:  # noqa: PYI063
    """Compare this member against another enum or a string.

    Args:
        __value (object): Another enum member or a string holding a member name.

    Returns:
        bool: True if the other enum matches by name and value, or the string matches this member's name.
    """
    if isinstance(__value, Enum):
        return self.name == __value.name and self.value == __value.value
    elif isinstance(__value, str):
        return self.name == __value
    else:
        return False

__str__

__str__() -> str

Return the member as ClassName.MEMBER.

Returns:

Name Type Description
str str

Human-readable identifier of the member.

Source code in spineps/seg_enums.py
def __str__(self) -> str:
    """Return the member as ``ClassName.MEMBER``.

    Returns:
        str: Human-readable identifier of the member.
    """
    return f"{type(self).__name__}.{self.name}"

__repr__

__repr__() -> str

Return the same string as :meth:__str__.

Returns:

Name Type Description
str str

Human-readable identifier of the member.

Source code in spineps/seg_enums.py
def __repr__(self) -> str:
    """Return the same string as :meth:`__str__`.

    Returns:
        str: Human-readable identifier of the member.
    """
    return str(self)

__hash__

__hash__() -> int

Return the member's integer value as its hash.

Returns:

Name Type Description
int int

The member's value, used for hashing.

Source code in spineps/seg_enums.py
def __hash__(self) -> int:
    """Return the member's integer value as its hash.

    Returns:
        int: The member's value, used for hashing.
    """
    return self.value

Modality

Bases: Enum_Compare

Image modality of an input scan.

Members cover the MRI sequences and other image types SPINEPS can handle, e.g. T2-weighted (T2w), T1-weighted (T1w), Vibe/Dixon, CT, an existing segmentation (SEG), multi-planar reconstruction (MPR), proton density (PD) and FLAIR.

Source code in spineps/seg_enums.py
class Modality(Enum_Compare):
    """Image modality of an input scan.

    Members cover the MRI sequences and other image types SPINEPS can handle, e.g. T2-weighted (T2w),
    T1-weighted (T1w), Vibe/Dixon, CT, an existing segmentation (SEG), multi-planar reconstruction (MPR),
    proton density (PD) and FLAIR.
    """

    T2w = auto()
    T1w = auto()
    Vibe = auto()
    CT = auto()
    SEG = auto()
    MPR = auto()
    PD = auto()
    FLAIR = auto()

    @classmethod
    def format_keys(cls, modalities: Self | list[Self]) -> list[str]:
        """Map modality members to the BIDS/file-name string keys that denote them.

        Args:
            modalities (Self | list[Self]): A single modality member or a list of them.

        Returns:
            list[str]: All file-name/format keys associated with the given modalities.

        Raises:
            NotImplementedError: If a modality has no associated keys defined.
        """
        if not isinstance(modalities, list):
            modalities = [modalities]
        result = []
        for modality in modalities:
            if modality == Modality.CT:
                result += ["CT", "ct"]
            elif modality == Modality.SEG:
                result += ["msk", "seg"]
            elif modality == Modality.T1w:
                result += ["T1w", "t1", "T1", "T1c"]
            elif modality == Modality.T2w:
                result += ["T2w", "dixon", "mr", "t2", "T2", "T2c"]
            elif modality == Modality.Vibe:
                result += ["t1dixon", "vibe", "mevibe", "GRE"]
            elif modality == Modality.MPR:
                result += ["mpr", "MPR", "Mpr"]
            else:
                raise NotImplementedError(modality)
        return result

format_keys classmethod

format_keys(modalities: Self | list[Self]) -> list[str]

Map modality members to the BIDS/file-name string keys that denote them.

Parameters:

Name Type Description Default
modalities Self | list[Self]

A single modality member or a list of them.

required

Returns:

Type Description
list[str]

list[str]: All file-name/format keys associated with the given modalities.

Raises:

Type Description
NotImplementedError

If a modality has no associated keys defined.

Source code in spineps/seg_enums.py
@classmethod
def format_keys(cls, modalities: Self | list[Self]) -> list[str]:
    """Map modality members to the BIDS/file-name string keys that denote them.

    Args:
        modalities (Self | list[Self]): A single modality member or a list of them.

    Returns:
        list[str]: All file-name/format keys associated with the given modalities.

    Raises:
        NotImplementedError: If a modality has no associated keys defined.
    """
    if not isinstance(modalities, list):
        modalities = [modalities]
    result = []
    for modality in modalities:
        if modality == Modality.CT:
            result += ["CT", "ct"]
        elif modality == Modality.SEG:
            result += ["msk", "seg"]
        elif modality == Modality.T1w:
            result += ["T1w", "t1", "T1", "T1c"]
        elif modality == Modality.T2w:
            result += ["T2w", "dixon", "mr", "t2", "T2", "T2c"]
        elif modality == Modality.Vibe:
            result += ["t1dixon", "vibe", "mevibe", "GRE"]
        elif modality == Modality.MPR:
            result += ["mpr", "MPR", "Mpr"]
        else:
            raise NotImplementedError(modality)
    return result

Acquisition

Bases: Enum_Compare

Acquisition plane of a scan.

Members denote the imaging plane: sag (sagittal), cor (coronal), ax (axial) and iso (isotropic / no dominant plane).

Source code in spineps/seg_enums.py
class Acquisition(Enum_Compare):
    """Acquisition plane of a scan.

    Members denote the imaging plane: ``sag`` (sagittal), ``cor`` (coronal), ``ax`` (axial)
    and ``iso`` (isotropic / no dominant plane).
    """

    sag = auto()
    cor = auto()
    ax = auto()
    iso = auto()

    @classmethod
    def format_keys(cls, acquisition: Self) -> list[str]:
        """Map an acquisition member to the file-name string keys that denote it.

        Args:
            acquisition (Self): The acquisition plane member.

        Returns:
            list[str]: All file-name/format keys associated with the given acquisition.

        Raises:
            NotImplementedError: If the acquisition has no associated keys defined.
        """
        if acquisition == Acquisition.ax:
            return ["axial", "ax", "axl"]
        elif acquisition == Acquisition.cor:
            return ["coronal", "cor"]
        elif acquisition == Acquisition.sag:
            return ["sagittal", "sag"]
        elif acquisition == Acquisition.iso:
            return ["iso", "ISO"]
        else:
            raise NotImplementedError(acquisition)

format_keys classmethod

format_keys(acquisition: Self) -> list[str]

Map an acquisition member to the file-name string keys that denote it.

Parameters:

Name Type Description Default
acquisition Self

The acquisition plane member.

required

Returns:

Type Description
list[str]

list[str]: All file-name/format keys associated with the given acquisition.

Raises:

Type Description
NotImplementedError

If the acquisition has no associated keys defined.

Source code in spineps/seg_enums.py
@classmethod
def format_keys(cls, acquisition: Self) -> list[str]:
    """Map an acquisition member to the file-name string keys that denote it.

    Args:
        acquisition (Self): The acquisition plane member.

    Returns:
        list[str]: All file-name/format keys associated with the given acquisition.

    Raises:
        NotImplementedError: If the acquisition has no associated keys defined.
    """
    if acquisition == Acquisition.ax:
        return ["axial", "ax", "axl"]
    elif acquisition == Acquisition.cor:
        return ["coronal", "cor"]
    elif acquisition == Acquisition.sag:
        return ["sagittal", "sag"]
    elif acquisition == Acquisition.iso:
        return ["iso", "ISO"]
    else:
        raise NotImplementedError(acquisition)

SpinepsPhase

Bases: Enum_Compare

Stage of the SPINEPS pipeline: semantic segmentation, vertebra instance segmentation or labeling.

Source code in spineps/seg_enums.py
class SpinepsPhase(Enum_Compare):
    """Stage of the SPINEPS pipeline: semantic segmentation, vertebra instance segmentation or labeling."""

    SEMANTIC = auto()
    INSTANCE = auto()
    LABELING = auto()

ModelType

Bases: Enum_Compare

Kind of model backing an inference config: an nnU-Net, a plain U-Net or a classifier.

Source code in spineps/seg_enums.py
class ModelType(Enum_Compare):
    """Kind of model backing an inference config: an nnU-Net, a plain U-Net or a classifier."""

    nnunet = auto()
    unet = auto()
    classifier = auto()

InputType

Bases: Enum_Compare

Type of input channel fed to a model.

img is the default image input and seg a segmentation input. The remaining members are the Dixon/Vibe channels: in-phase (ip), out-of-phase (oop), water and fat.

Source code in spineps/seg_enums.py
class InputType(Enum_Compare):
    """Type of input channel fed to a model.

    ``img`` is the default image input and ``seg`` a segmentation input. The remaining members
    are the Dixon/Vibe channels: in-phase (``ip``), out-of-phase (``oop``), ``water`` and ``fat``.
    """

    img = auto()  # default: image input
    seg = auto()  # segmentation input
    # For Vibe
    ip = auto()  # inphase
    oop = auto()  # out of phase
    water = auto()  # water
    fat = auto()  # fat

OutputType

Bases: Enum_Compare

Type of model output: a segmentation (seg), softmax logits or an uncertainty map (unc).

Source code in spineps/seg_enums.py
class OutputType(Enum_Compare):
    """Type of model output: a segmentation (``seg``), softmax logits or an uncertainty map (``unc``)."""

    seg = auto()
    # seg_modelres = auto()
    softmax_logits = auto()
    unc = auto()

ErrCode

Bases: Enum_Compare

Status/error codes returned by pipeline steps.

Indicates success (OK), that outputs already exist (ALL_DONE), a model/input compatibility problem (COMPATIBILITY), an unknown failure (UNKNOWN), an empty mask or input (EMPTY) or mismatched shapes (SHAPE).

Source code in spineps/seg_enums.py
class ErrCode(Enum_Compare):
    """Status/error codes returned by pipeline steps.

    Indicates success (``OK``), that outputs already exist (``ALL_DONE``), a model/input compatibility
    problem (``COMPATIBILITY``), an unknown failure (``UNKNOWN``), an empty mask or input (``EMPTY``)
    or mismatched shapes (``SHAPE``).
    """

    OK = auto()
    ALL_DONE = auto()  # outputs are already there
    COMPATIBILITY = auto()  # compatibility issue between model and input
    UNKNOWN = auto()  # unknown issue
    EMPTY = auto()  # issue that the mask or input is empty
    SHAPE = auto()  # issue that shapes do not match

spineps.utils.seg_modelconfig

spineps.utils.seg_modelconfig

Inference configuration model: parses and holds the per-model settings stored in inference_config.json files.

Segmentation_Inference_Config

Bucket for saving Inference Config data

Source code in spineps/utils/seg_modelconfig.py
class Segmentation_Inference_Config:
    """Bucket for saving Inference Config data"""

    def __init__(
        self,
        logger: Logger_Interface | None,
        log_name: str,
        modality: str | tuple[str],
        acquisition: str,
        modeltype: str,
        model_expected_orientation: AX_CODES,
        available_folds: int | str | tuple[str] | tuple[int],
        inference_augmentation: bool,
        resolution_range: ZOOMS | tuple[ZOOMS, ZOOMS],
        default_step_size: float,
        labels: dict,
        expected_inputs: list[InputType | str] = [InputType.img],  # noqa: B006
        has_c1=False,
        needs_corp=False,
        sacrum_ids=DEFAULT_SACRUM_IDS,
        cutout_size=DEFAULT_CUTOUT_SIZE,
        corpus_size_cleaning=DEFAULT_CORPUS_SIZE_CLEANING,
        corpus_border_threshold=DEFAULT_CORPUS_BORDER_THRESHOLD,
        vert_size_threshold=DEFAULT_VERT_SIZE_THRESHOLD,
        mapping=None,
        **kwargs,
    ):
        """Build an inference config from raw (typically JSON-decoded) values.

        String fields are resolved to the corresponding enum members and the label dictionaries are converted to
        integer label ids. Voxel-count cleaning thresholds are scaled by the resolution's voxel volume so they stay
        physically meaningful across resolutions.

        Args:
            logger (Logger_Interface | None): Logger for diagnostics; unknown extra kwargs are reported through it.
            log_name (str): Name used as the logger prefix and to identify this config.
            modality (str | tuple[str]): One or more modality names (see :class:`Modality`).
            acquisition (str): Acquisition plane name (see :class:`Acquisition`).
            modeltype (str): Model type name (see :class:`ModelType`).
            model_expected_orientation (AX_CODES): Axis-code orientation the model expects its input in.
            available_folds (int | str | tuple[str] | tuple[int]): Folds available for inference/ensembling.
            inference_augmentation (bool): Whether to apply test-time augmentation during inference.
            resolution_range (ZOOMS | tuple[ZOOMS, ZOOMS]): Target voxel spacing, either a single zoom or a
                (min, max) range.
            default_step_size (float): Default sliding-window step size used during inference.
            labels (dict): Mapping of raw label keys to label names/ids resolved via ``Location``/``v_name2idx``.
            expected_inputs (list[InputType | str], optional): Input channels the model expects. Defaults to
                ``[InputType.img]``.
            has_c1 (bool, optional): Whether the model segments the C1 vertebra. Defaults to False.
            needs_corp (bool, optional): Whether the model needs the vertebral corpus present. Defaults to False.
            sacrum_ids (tuple, optional): Label ids treated as sacrum. Defaults to ``DEFAULT_SACRUM_IDS``.
            cutout_size (tuple, optional): Crop/cutout size in voxels. Defaults to ``DEFAULT_CUTOUT_SIZE``.
            corpus_size_cleaning (int, optional): Minimum corpus component size in voxels before resolution
                scaling. Defaults to ``DEFAULT_CORPUS_SIZE_CLEANING``.
            corpus_border_threshold (int, optional): Border distance threshold for corpus cleaning. Defaults to
                ``DEFAULT_CORPUS_BORDER_THRESHOLD``.
            vert_size_threshold (int, optional): Minimum vertebra size in voxels before resolution scaling.
                Defaults to ``DEFAULT_VERT_SIZE_THRESHOLD``.
            mapping (dict | None, optional): Remapping of raw model label ids onto canonical ids. Defaults to a
                copy of ``DEFAULT_LABEL_MAPPING``.
            **kwargs: Ignored extra configuration keys, reported via ``logger``.

        Raises:
            KeyError: If a label name in ``labels`` cannot be resolved to a known label id.
        """
        scaling_factor = np.prod(resolution_range) if len(resolution_range) == SPATIAL_DIMS else np.prod(resolution_range[0])
        if mapping is None:
            mapping = dict(DEFAULT_LABEL_MAPPING)
        if not isinstance(modality, (list, tuple)):
            modality = [modality]

        self.log_name: str = log_name
        self.modalities: list[Modality] = [Modality[m] for m in modality]
        self.acquisition: Acquisition = Acquisition[acquisition]
        self.modeltype: ModelType = ModelType[modeltype]
        self.model_expected_orientation: AX_CODES = tuple(model_expected_orientation)  # type:ignore
        self.resolution_range = resolution_range
        self.available_folds: int | str | tuple[str] | tuple[int] = available_folds
        self.inference_augmentation: bool = inference_augmentation
        self.default_step_size = float(default_step_size)
        self.expected_inputs = [InputType[i] if isinstance(i, str) else i for i in expected_inputs]  # type: ignore
        self.has_c1 = has_c1
        self.needs_corp = needs_corp
        self.sacrum_ids = sacrum_ids
        self.cutout_size = cutout_size
        self.corpus_size_cleaning = corpus_size_cleaning * scaling_factor  # voxel threshold * resolution
        self.corpus_border_threshold = corpus_border_threshold
        self.vert_size_threshold = vert_size_threshold * scaling_factor  # voxel threshold * resolution
        self.mapping = mapping
        names = [member.name for member in Location]
        try:
            self.segmentation_labels = {
                int(k): Location[v].value if v in names else v_name2idx[v] if v in v_name2idx else int(v) for k, v in labels.items()
            }
        except KeyError as e:
            if logger is not None:
                logger.print("not a valid label!", Log_Type.FAIL)
            raise e  # noqa: TRY201

        if logger is not None:
            logger.prefix = self.log_name
            for k in kwargs:
                logger.print(f"Ignored inference config argument {k}", Log_Type.STRANGE)

    def str_representation(self, short: bool = False) -> str:
        """Render the config's attributes as a comma-separated ``'key'=value`` string.

        Args:
            short (bool, optional): If True, include only the modalities, acquisition and resolution range.
                Defaults to False (all attributes except ``log_name``).

        Returns:
            str: The formatted representation of the selected attributes.
        """
        to_print = self.__dict__ if not short else ["modalities", "acquisition", "resolution_range"]
        sb = []
        for key in self.__dict__:
            if key == "log_name" or key not in to_print:
                continue
            val = self.__dict__[key]
            val = str(val) if not isinstance(val, list) else [str(e) for e in val]
            sb.append(f"'{key!s}'={val}")

        return ", ".join(sb)

    def __str__(self) -> str:
        """Return the full string representation.

        Returns:
            str: All attributes formatted via :meth:`str_representation`.
        """
        return self.str_representation()

    def __repr__(self) -> str:
        """Return the short string representation.

        Returns:
            str: The key attributes formatted via :meth:`str_representation` with ``short=True``.
        """
        return self.str_representation(short=True)

__init__

__init__(
    logger: Logger_Interface | None,
    log_name: str,
    modality: str | tuple[str],
    acquisition: str,
    modeltype: str,
    model_expected_orientation: AX_CODES,
    available_folds: int | str | tuple[str] | tuple[int],
    inference_augmentation: bool,
    resolution_range: ZOOMS | tuple[ZOOMS, ZOOMS],
    default_step_size: float,
    labels: dict,
    expected_inputs: list[InputType | str] = [
        InputType.img
    ],
    has_c1=False,
    needs_corp=False,
    sacrum_ids=DEFAULT_SACRUM_IDS,
    cutout_size=DEFAULT_CUTOUT_SIZE,
    corpus_size_cleaning=DEFAULT_CORPUS_SIZE_CLEANING,
    corpus_border_threshold=DEFAULT_CORPUS_BORDER_THRESHOLD,
    vert_size_threshold=DEFAULT_VERT_SIZE_THRESHOLD,
    mapping=None,
    **kwargs,
)

Build an inference config from raw (typically JSON-decoded) values.

String fields are resolved to the corresponding enum members and the label dictionaries are converted to integer label ids. Voxel-count cleaning thresholds are scaled by the resolution's voxel volume so they stay physically meaningful across resolutions.

Parameters:

Name Type Description Default
logger Logger_Interface | None

Logger for diagnostics; unknown extra kwargs are reported through it.

required
log_name str

Name used as the logger prefix and to identify this config.

required
modality str | tuple[str]

One or more modality names (see :class:Modality).

required
acquisition str

Acquisition plane name (see :class:Acquisition).

required
modeltype str

Model type name (see :class:ModelType).

required
model_expected_orientation AX_CODES

Axis-code orientation the model expects its input in.

required
available_folds int | str | tuple[str] | tuple[int]

Folds available for inference/ensembling.

required
inference_augmentation bool

Whether to apply test-time augmentation during inference.

required
resolution_range ZOOMS | tuple[ZOOMS, ZOOMS]

Target voxel spacing, either a single zoom or a (min, max) range.

required
default_step_size float

Default sliding-window step size used during inference.

required
labels dict

Mapping of raw label keys to label names/ids resolved via Location/v_name2idx.

required
expected_inputs list[InputType | str]

Input channels the model expects. Defaults to [InputType.img].

[img]
has_c1 bool

Whether the model segments the C1 vertebra. Defaults to False.

False
needs_corp bool

Whether the model needs the vertebral corpus present. Defaults to False.

False
sacrum_ids tuple

Label ids treated as sacrum. Defaults to DEFAULT_SACRUM_IDS.

DEFAULT_SACRUM_IDS
cutout_size tuple

Crop/cutout size in voxels. Defaults to DEFAULT_CUTOUT_SIZE.

DEFAULT_CUTOUT_SIZE
corpus_size_cleaning int

Minimum corpus component size in voxels before resolution scaling. Defaults to DEFAULT_CORPUS_SIZE_CLEANING.

DEFAULT_CORPUS_SIZE_CLEANING
corpus_border_threshold int

Border distance threshold for corpus cleaning. Defaults to DEFAULT_CORPUS_BORDER_THRESHOLD.

DEFAULT_CORPUS_BORDER_THRESHOLD
vert_size_threshold int

Minimum vertebra size in voxels before resolution scaling. Defaults to DEFAULT_VERT_SIZE_THRESHOLD.

DEFAULT_VERT_SIZE_THRESHOLD
mapping dict | None

Remapping of raw model label ids onto canonical ids. Defaults to a copy of DEFAULT_LABEL_MAPPING.

None
**kwargs

Ignored extra configuration keys, reported via logger.

{}

Raises:

Type Description
KeyError

If a label name in labels cannot be resolved to a known label id.

Source code in spineps/utils/seg_modelconfig.py
def __init__(
    self,
    logger: Logger_Interface | None,
    log_name: str,
    modality: str | tuple[str],
    acquisition: str,
    modeltype: str,
    model_expected_orientation: AX_CODES,
    available_folds: int | str | tuple[str] | tuple[int],
    inference_augmentation: bool,
    resolution_range: ZOOMS | tuple[ZOOMS, ZOOMS],
    default_step_size: float,
    labels: dict,
    expected_inputs: list[InputType | str] = [InputType.img],  # noqa: B006
    has_c1=False,
    needs_corp=False,
    sacrum_ids=DEFAULT_SACRUM_IDS,
    cutout_size=DEFAULT_CUTOUT_SIZE,
    corpus_size_cleaning=DEFAULT_CORPUS_SIZE_CLEANING,
    corpus_border_threshold=DEFAULT_CORPUS_BORDER_THRESHOLD,
    vert_size_threshold=DEFAULT_VERT_SIZE_THRESHOLD,
    mapping=None,
    **kwargs,
):
    """Build an inference config from raw (typically JSON-decoded) values.

    String fields are resolved to the corresponding enum members and the label dictionaries are converted to
    integer label ids. Voxel-count cleaning thresholds are scaled by the resolution's voxel volume so they stay
    physically meaningful across resolutions.

    Args:
        logger (Logger_Interface | None): Logger for diagnostics; unknown extra kwargs are reported through it.
        log_name (str): Name used as the logger prefix and to identify this config.
        modality (str | tuple[str]): One or more modality names (see :class:`Modality`).
        acquisition (str): Acquisition plane name (see :class:`Acquisition`).
        modeltype (str): Model type name (see :class:`ModelType`).
        model_expected_orientation (AX_CODES): Axis-code orientation the model expects its input in.
        available_folds (int | str | tuple[str] | tuple[int]): Folds available for inference/ensembling.
        inference_augmentation (bool): Whether to apply test-time augmentation during inference.
        resolution_range (ZOOMS | tuple[ZOOMS, ZOOMS]): Target voxel spacing, either a single zoom or a
            (min, max) range.
        default_step_size (float): Default sliding-window step size used during inference.
        labels (dict): Mapping of raw label keys to label names/ids resolved via ``Location``/``v_name2idx``.
        expected_inputs (list[InputType | str], optional): Input channels the model expects. Defaults to
            ``[InputType.img]``.
        has_c1 (bool, optional): Whether the model segments the C1 vertebra. Defaults to False.
        needs_corp (bool, optional): Whether the model needs the vertebral corpus present. Defaults to False.
        sacrum_ids (tuple, optional): Label ids treated as sacrum. Defaults to ``DEFAULT_SACRUM_IDS``.
        cutout_size (tuple, optional): Crop/cutout size in voxels. Defaults to ``DEFAULT_CUTOUT_SIZE``.
        corpus_size_cleaning (int, optional): Minimum corpus component size in voxels before resolution
            scaling. Defaults to ``DEFAULT_CORPUS_SIZE_CLEANING``.
        corpus_border_threshold (int, optional): Border distance threshold for corpus cleaning. Defaults to
            ``DEFAULT_CORPUS_BORDER_THRESHOLD``.
        vert_size_threshold (int, optional): Minimum vertebra size in voxels before resolution scaling.
            Defaults to ``DEFAULT_VERT_SIZE_THRESHOLD``.
        mapping (dict | None, optional): Remapping of raw model label ids onto canonical ids. Defaults to a
            copy of ``DEFAULT_LABEL_MAPPING``.
        **kwargs: Ignored extra configuration keys, reported via ``logger``.

    Raises:
        KeyError: If a label name in ``labels`` cannot be resolved to a known label id.
    """
    scaling_factor = np.prod(resolution_range) if len(resolution_range) == SPATIAL_DIMS else np.prod(resolution_range[0])
    if mapping is None:
        mapping = dict(DEFAULT_LABEL_MAPPING)
    if not isinstance(modality, (list, tuple)):
        modality = [modality]

    self.log_name: str = log_name
    self.modalities: list[Modality] = [Modality[m] for m in modality]
    self.acquisition: Acquisition = Acquisition[acquisition]
    self.modeltype: ModelType = ModelType[modeltype]
    self.model_expected_orientation: AX_CODES = tuple(model_expected_orientation)  # type:ignore
    self.resolution_range = resolution_range
    self.available_folds: int | str | tuple[str] | tuple[int] = available_folds
    self.inference_augmentation: bool = inference_augmentation
    self.default_step_size = float(default_step_size)
    self.expected_inputs = [InputType[i] if isinstance(i, str) else i for i in expected_inputs]  # type: ignore
    self.has_c1 = has_c1
    self.needs_corp = needs_corp
    self.sacrum_ids = sacrum_ids
    self.cutout_size = cutout_size
    self.corpus_size_cleaning = corpus_size_cleaning * scaling_factor  # voxel threshold * resolution
    self.corpus_border_threshold = corpus_border_threshold
    self.vert_size_threshold = vert_size_threshold * scaling_factor  # voxel threshold * resolution
    self.mapping = mapping
    names = [member.name for member in Location]
    try:
        self.segmentation_labels = {
            int(k): Location[v].value if v in names else v_name2idx[v] if v in v_name2idx else int(v) for k, v in labels.items()
        }
    except KeyError as e:
        if logger is not None:
            logger.print("not a valid label!", Log_Type.FAIL)
        raise e  # noqa: TRY201

    if logger is not None:
        logger.prefix = self.log_name
        for k in kwargs:
            logger.print(f"Ignored inference config argument {k}", Log_Type.STRANGE)

str_representation

str_representation(short: bool = False) -> str

Render the config's attributes as a comma-separated 'key'=value string.

Parameters:

Name Type Description Default
short bool

If True, include only the modalities, acquisition and resolution range. Defaults to False (all attributes except log_name).

False

Returns:

Name Type Description
str str

The formatted representation of the selected attributes.

Source code in spineps/utils/seg_modelconfig.py
def str_representation(self, short: bool = False) -> str:
    """Render the config's attributes as a comma-separated ``'key'=value`` string.

    Args:
        short (bool, optional): If True, include only the modalities, acquisition and resolution range.
            Defaults to False (all attributes except ``log_name``).

    Returns:
        str: The formatted representation of the selected attributes.
    """
    to_print = self.__dict__ if not short else ["modalities", "acquisition", "resolution_range"]
    sb = []
    for key in self.__dict__:
        if key == "log_name" or key not in to_print:
            continue
        val = self.__dict__[key]
        val = str(val) if not isinstance(val, list) else [str(e) for e in val]
        sb.append(f"'{key!s}'={val}")

    return ", ".join(sb)

__str__

__str__() -> str

Return the full string representation.

Returns:

Name Type Description
str str

All attributes formatted via :meth:str_representation.

Source code in spineps/utils/seg_modelconfig.py
def __str__(self) -> str:
    """Return the full string representation.

    Returns:
        str: All attributes formatted via :meth:`str_representation`.
    """
    return self.str_representation()

__repr__

__repr__() -> str

Return the short string representation.

Returns:

Name Type Description
str str

The key attributes formatted via :meth:str_representation with short=True.

Source code in spineps/utils/seg_modelconfig.py
def __repr__(self) -> str:
    """Return the short string representation.

    Returns:
        str: The key attributes formatted via :meth:`str_representation` with ``short=True``.
    """
    return self.str_representation(short=True)

load_inference_config

load_inference_config(
    json_dir: str | Path,
    logger: Logger_Interface | None = None,
) -> Segmentation_Inference_Config

Load an inference configuration from a JSON file.

Parameters:

Name Type Description Default
json_dir str | Path

Path to the inference_config.json file.

required
logger Logger_Interface | None

Logger forwarded to the config for diagnostics. Defaults to None.

None

Returns:

Name Type Description
Segmentation_Inference_Config Segmentation_Inference_Config

The config built from the file's contents.

Source code in spineps/utils/seg_modelconfig.py
def load_inference_config(json_dir: str | Path, logger: Logger_Interface | None = None) -> Segmentation_Inference_Config:
    """Load an inference configuration from a JSON file.

    Args:
        json_dir (str | Path): Path to the ``inference_config.json`` file.
        logger (Logger_Interface | None, optional): Logger forwarded to the config for diagnostics. Defaults to None.

    Returns:
        Segmentation_Inference_Config: The config built from the file's contents.
    """
    with open(str(json_dir), encoding="utf-8") as json_file:
        inference_config = json.load(json_file)
    return Segmentation_Inference_Config(**inference_config, logger=logger)