Source code for autods_pet.ops.morphology
"""Distance-transform based morphology, robust to anisotropic spacing."""
from __future__ import annotations
import SimpleITK as sitk
[docs]
def signed_distance_mm(mask: sitk.Image) -> sitk.Image:
"""Compute a signed distance map in mm from a binary mask.
Parameters
----------
mask : sitk.Image
Binary mask (non-zero values are foreground).
Returns
-------
sitk.Image
Float image where positive values are *inside* the mask and negative
values are *outside*, in physical mm units (respects voxel spacing).
"""
mask = sitk.Cast(mask != 0, sitk.sitkUInt8)
return sitk.SignedMaurerDistanceMap(
mask,
insideIsPositive=True,
squaredDistance=False,
useImageSpacing=True,
)
[docs]
def erode_mask_mm(
mask: sitk.Image,
radius_mm: float,
*,
dist: sitk.Image | None = None,
) -> sitk.Image:
"""Erode a binary mask by *radius_mm* using a distance transform.
Pass a pre-computed *dist* (from :func:`signed_distance_mm`) to avoid
recomputing it when eroding and dilating the same mask.
Parameters
----------
mask : sitk.Image
Binary mask (non-zero values are foreground).
radius_mm : float
Erosion radius in physical mm units.
dist : sitk.Image or None
Pre-computed signed distance map. When ``None`` (default), it is
computed internally via :func:`signed_distance_mm`.
Returns
-------
sitk.Image
Eroded binary mask (uint8).
"""
mask = sitk.Cast(mask != 0, sitk.sitkUInt8)
if radius_mm <= 0:
return mask
if dist is None:
dist = signed_distance_mm(mask)
eroded = sitk.GreaterEqual(dist, float(radius_mm))
return sitk.Cast(eroded, sitk.sitkUInt8)
[docs]
def dilate_mask_mm(
mask: sitk.Image,
radius_mm: float,
*,
dist: sitk.Image | None = None,
) -> sitk.Image:
"""Dilate a binary mask by *radius_mm* using a distance transform.
Pass a pre-computed *dist* (from :func:`signed_distance_mm`) to avoid
recomputing it when eroding and dilating the same mask.
Parameters
----------
mask : sitk.Image
Binary mask (non-zero values are foreground).
radius_mm : float
Dilation radius in physical mm units.
dist : sitk.Image or None
Pre-computed signed distance map. When ``None`` (default), it is
computed internally via :func:`signed_distance_mm`.
Returns
-------
sitk.Image
Dilated binary mask (uint8).
"""
mask = sitk.Cast(mask != 0, sitk.sitkUInt8)
if radius_mm <= 0:
return mask
if dist is None:
dist = signed_distance_mm(mask)
dilated = sitk.GreaterEqual(dist, float(-radius_mm))
return sitk.Cast(dilated, sitk.sitkUInt8)