Source code for autods_pet.roi.lumbar_vb
"""Lumbar vertebral body: mask refinement and PET statistics."""
from __future__ import annotations
import SimpleITK as sitk
from .. import labels
from ..imaging.geometry import check_same_geometry
from ..ops.masks import label_union
from ..ops.morphology import erode_mask_mm
from ..ops.stats import compute_stats, shrinkage_report
from ..results import ROIResult
[docs]
class LumbarVB:
"""Lumbar vertebral body ROI extraction and refinement.
Parameters
----------
lumbar_labels : list[int] or None
TotalSegmentator labels for the target vertebrae.
Defaults to L3, L4, L5.
erosion_mm : float
Physical erosion radius in mm.
stats : list[str] or None
Statistics to compute (e.g. ``["p95"]``).
Defaults to ``["p95"]``.
"""
def __init__(
self,
lumbar_labels: list[int] | None = None,
erosion_mm: float = 3.0,
stats: list[str] | None = None,
) -> None:
self.lumbar_labels = (
lumbar_labels if lumbar_labels is not None else labels.LUMBAR_L3_L5
)
self.erosion_mm = erosion_mm
self.stats = stats if stats is not None else ["p95"]
[docs]
def refine(self, whole_seg: sitk.Image, vert_body_seg: sitk.Image) -> ROIResult:
"""Refine TotalSegmentator vertebra labels into a lumbar VB mask.
Pipeline: union of lumbar labels -> intersection with vertebral body
binary mask -> physical erosion.
Parameters
----------
whole_seg : sitk.Image
TotalSegmentator multilabel segmentation.
vert_body_seg : sitk.Image
Binary vertebral body segmentation.
Returns
-------
ROIResult
Result with ``refined_mask`` and ``shrinkage`` populated.
"""
vertebra_mask = label_union(whole_seg, self.lumbar_labels)
vb_bin = sitk.Cast(vert_body_seg != 0, sitk.sitkUInt8)
vb_mask = sitk.Cast(sitk.And(vertebra_mask, vb_bin), sitk.sitkUInt8)
vb_eroded = erode_mask_mm(vb_mask, self.erosion_mm)
return ROIResult(
refined_mask=vb_eroded,
shrinkage=shrinkage_report(vertebra_mask, vb_eroded),
)