Source code for pyRadPlan.core.np2sitk
"""Helpers for conversion between numpy and SimpleITK."""
from typing import Literal
import SimpleITK as sitk
import numpy as np
import array_api_compat
from array_api_compat import numpy as xnp
from ._grids import Grid
from numpy.typing import NDArray
from ..core.xp_utils.typing import Array
from ..core.xp_utils import to_numpy, from_numpy
[docs]
def sitk_mask_to_linear_indices(mask: sitk.Image, order="sitk") -> NDArray:
"""
Convert a SimpleITK mask to linear indices.
Parameters
----------
mask : sitk.Image
The SimpleITK image mask to be converted.
order : str, optional
The ordering of the indices. Can be 'sitk' for Fortran-like index
ordering or 'numpy' for C-like index ordering. Default is 'sitk'.
Returns
-------
NDArray
A 1D numpy array of linear indices where the mask is non-zero.
Raises
------
ValueError
If the ordering is not 'sitk' or 'numpy'.
"""
arr = sitk.GetArrayViewFromImage(mask)
if order == "sitk":
return np.nonzero(arr.ravel(order="F"))[0]
if order == "numpy":
return np.flatnonzero(arr)
raise ValueError("Invalid ordering. Must be 'sitk' or 'numpy'.")
[docs]
def linear_indices_to_sitk_mask(indices: Array, ref_image: sitk.Image, order="sitk") -> sitk.Image:
"""
Convert linear indices to a SimpleITK mask.
Parameters
----------
indices : Array
A 1D Array API conform array of linear indices where the mask is non-zero.
ref_image : sitk.Image
The reference image on which the mask is defined.
order : str, optional
The ordering of the indices. Can be 'sitk' for Fortran-like index
ordering or 'numpy' for C-like index ordering. Default is 'sitk'.
Returns
-------
sitk.Image
A SimpleITK image mask with the indices set to non-zero.
Raises
------
ValueError
If the ordering is not 'sitk' or 'numpy'.
"""
indices = to_numpy(indices)
arr: NDArray = xnp.zeros_like(sitk.GetArrayViewFromImage(ref_image), dtype=xnp.uint8)
if order == "sitk":
arr.T.flat[indices] = 1
elif order == "numpy":
arr.flat[indices] = 1
else:
raise ValueError("Invalid ordering. Must be 'sitk' or 'numpy'.")
mask = sitk.GetImageFromArray(arr)
mask.CopyInformation(ref_image)
return mask
[docs]
def linear_indices_to_grid_coordinates(
indices: Array,
grid: Grid,
index_type: Literal["numpy", "sitk"] = "numpy",
dtype: np.dtype = np.float64,
) -> Array:
"""
Convert linear indices to gridcoordinates.
Parameters
----------
indices : Array
A 1D Array API conform array of linear indices where the mask is non-zero.
grid : Grid
The image grid on which the indices lie.
index_type : Literal["numpy", "sitk"], optional
The ordering of the indices. Can be 'sitk' for Fortran-like index
ordering or 'numpy' for C-like index ordering. Default is 'numpy'.
dtype : np.dtype, optional
The data type of the output coordinates. Default is np.float64.
Returns
-------
Array
A 2D Array API conform array array of image coordinates.
"""
xp = array_api_compat.array_namespace(indices)
# this is a manual reimplementation of np.unravel_index
# to avoid the overhead of creating a tuple of arrays
if index_type == "numpy":
_, d1, d2 = grid.dimensions[::-1]
order = [0, 1, 2]
elif index_type == "sitk":
_, d1, d2 = grid.dimensions
order = [2, 1, 0]
else:
raise ValueError("Invalid index type. Must be 'numpy' or 'sitk'.")
indices = to_numpy(indices)
v = np.empty((3, np.asarray(indices).size), dtype=dtype)
tmp, v[order[0]] = np.divmod(indices, d2)
v[order[2]], v[order[1]] = np.divmod(tmp, d1)
spacing_diag = np.diag(
[grid.resolution["x"], grid.resolution["y"], grid.resolution["z"]]
).astype(dtype)
origin = grid.origin.astype(dtype)
physical_point = origin + np.matmul(np.matmul(grid.direction, spacing_diag), v).T
return from_numpy(xp, physical_point)
[docs]
def linear_indices_to_image_coordinates(
indices: Array,
image: sitk.Image,
index_type: Literal["numpy", "sitk"] = "numpy",
dtype: np.dtype = np.float64,
) -> Array:
"""
Convert linear indices to image coordinates.
Parameters
----------
indices : Array
A 1D Array API conform array of linear indices where the mask is non-zero.
image : sitk.Image
The reference image on which the mask is defined.
index_type : Literal["numpy", "sitk"], optional
The ordering of the indices. Can be 'sitk' for Fortran-like index
ordering or 'numpy' for C-like index ordering. Default is 'numpy'.
dtype : np.dtype, optional
The data type of the output coordinates. Default is np.float64.
Returns
-------
Array
A 2D Array API conform array of image coordinates.
"""
grid = Grid.from_sitk_image(image)
return linear_indices_to_grid_coordinates(indices, grid, index_type, dtype=dtype)