Source code for medipt.transforms.spatial.rotation_transform
from abc import ABC
from typing import Union, Tuple, List
import SimpleITK as sitk
import numpy as np
from .spatial_transform import SpatialTransform
from .random_affine_transform import RandomAffineTransform
[docs]class RotationTransform(SpatialTransform):
"""
Rotation transformation base class.
"""
def __init__(self,
dim: int = 3,
used_dimensions: bool = None,
seed: Union[np.random.RandomState, np.random.Generator, np.random.BitGenerator, int, None] = None,
legacy_random_state: bool = True,
*args, **kwargs):
"""
Initializer
:param dim: The dimension.
:param used_dimensions: Boolean list of which dimension indizes to use for the transformation.
:param args: Arguments passed to super init.
:param kwargs: Keyword arguments passed to super init.
"""
super(RotationTransform, self).__init__(dim, used_dimensions, seed, legacy_random_state, *args, **kwargs)
def _get_transform(self,
angles: Union[List[float], Tuple[float, ...], float],
*args, **kwargs):
"""
Returns the sitk transform based on the given parameters.
:param dim: The dimension.
:param angles: List of angles for each dimension (in radians).
:return: The sitk.AffineTransform().
"""
if not isinstance(angles, (list, tuple)):
angles = [angles]
assert isinstance(angles, (list, tuple)), 'Angles parameter must be a list of floats, one for each dimension.'
assert len(angles) in [1, self.dim], 'Angles must be a list of length 1 for 2D, or 3 for 3D.'
self.transform = sitk.AffineTransform(self.dim)
if isinstance(angles, (tuple, list)):
if len(angles) == 1:
# 2D
self.transform.Rotate(0, 1, angle=angles[0])
elif len(angles) > 1:
assert len(angles) == self.dim, f'angles must be a list of length {self.dim}.'
# 3D
# rotate about x axis
self.transform.Rotate(1, 2, angle=angles[0])
# rotate about y axis
self.transform.Rotate(0, 2, angle=angles[1])
# rotate about z axis
self.transform.Rotate(0, 1, angle=angles[2])
elif isinstance(angles, (int, float, np.ndarray)):
self.transform.Rotate(0, 1, angle=angles)
# return self.t
a = 1
[docs] def get_transform(self,
angles: Union[List[float], Tuple[float, ...], float],
*args, **kwargs):
self._get_transform(angles, *args, **kwargs)
# return t
[docs]class RandomRotation(RotationTransform, RandomAffineTransform):
"""
A rotation transformation with random angles (in radian).
"""
def __init__(self,
dim: int,
used_dimensions: bool = None,
# min_angles: Union[Union[List[Union[int, float]], Tuple[Union[int, float], ...]], int, float, np.integer, np.floating, np.ndarray, None] = None,
# max_angles: Union[Union[List[Union[int, float]], Tuple[Union[int, float], ...]], int, float, np.integer, np.floating, np.ndarray, None] = None,
seed: Union[np.random.RandomState, np.random.Generator, np.random.BitGenerator, int, None] = None,
legacy_random_state: bool = True,
*args, **kwargs):
"""
Initializer.
:param dim: The dimension.
:param random_angles: List of random angles per dimension. Random angle is calculated uniformly within [-random_angles[i], random_angles[i]]
:param args: Arguments passed to super init.
:param kwargs: Keyword arguments passed to super init.
"""
super(RandomRotation, self).__init__(dim, used_dimensions, seed, legacy_random_state, *args, **kwargs)
[docs] def get_random_transform(self,
min_angles: Union[Union[List[Union[int, float]], Tuple[Union[int, float], ...]], int, float, np.integer, np.floating, np.ndarray, None] = None,
max_angles: Union[Union[List[Union[int, float]], Tuple[Union[int, float], ...]], int, float, np.integer, np.floating, np.ndarray, None] = None,
transformation_dict: dict = None,
*args, **kwargs):
self._get_random_transform(min_angles, max_angles, transformation_dict=transformation_dict, *args, **kwargs)