Source code for monai.transforms.intensity.dictionary

# Copyright 2020 MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
A collection of dictionary-based wrappers around the "vanilla" transforms for intensity adjustment
defined in :py:class:`monai.transforms.intensity.array`.

Class names are ended with 'd' to denote dictionary-based transforms.
"""

from typing import Union, Optional, Tuple

import numpy as np

from monai.config import KeysCollection
from monai.transforms.compose import MapTransform, Randomizable
from monai.transforms.intensity.array import (
    NormalizeIntensity,
    ScaleIntensityRange,
    ThresholdIntensity,
    AdjustContrast,
    ShiftIntensity,
    ScaleIntensity,
    ScaleIntensityRangePercentiles,
)


[docs]class RandGaussianNoised(Randomizable, MapTransform): """ Dictionary-based version :py:class:`monai.transforms.RandGaussianNoise`. Add Gaussian noise to image. This transform assumes all the expected fields have same shape. Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` prob: Probability to add Gaussian noise. mean (float or array of floats): Mean or “centre” of the distribution. std: Standard deviation (spread) of distribution. """ def __init__(self, keys: KeysCollection, prob: float = 0.1, mean: float = 0.0, std: float = 0.1): super().__init__(keys) self.prob = prob self.mean = mean self.std = std self._do_transform = False self._noise = None
[docs] def randomize(self, im_shape) -> None: # type: ignore # see issue #495 self._do_transform = self.R.random() < self.prob self._noise = self.R.normal(self.mean, self.R.uniform(0, self.std), size=im_shape)
[docs] def __call__(self, data): d = dict(data) image_shape = d[self.keys[0]].shape # image shape from the first data key self.randomize(image_shape) if not self._do_transform: return d for key in self.keys: d[key] = d[key] + self._noise.astype(d[key].dtype) return d
[docs]class ShiftIntensityd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.ShiftIntensity`. """ def __init__(self, keys: KeysCollection, offset: float): """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` offset: offset value to shift the intensity of image. """ super().__init__(keys) self.shifter = ShiftIntensity(offset)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.shifter(d[key]) return d
[docs]class RandShiftIntensityd(Randomizable, MapTransform): """ Dictionary-based version :py:class:`monai.transforms.RandShiftIntensity`. """ def __init__(self, keys: KeysCollection, offsets: Union[Tuple[float, float], float], prob: float = 0.1): """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` offsets: offset range to randomly shift. if single number, offset value is picked from (-offsets, offsets). prob: probability of rotating. (Default 0.1, with 10% probability it returns a rotated array.) """ super().__init__(keys) self.offsets = (-offsets, offsets) if not isinstance(offsets, (list, tuple)) else offsets assert len(self.offsets) == 2, "offsets should be a number or pair of numbers." self.prob = prob self._do_transform = False
[docs] def randomize(self) -> None: # type: ignore # see issue #495 self._offset = self.R.uniform(low=self.offsets[0], high=self.offsets[1]) self._do_transform = self.R.random() < self.prob
[docs] def __call__(self, data): d = dict(data) self.randomize() if not self._do_transform: return d shifter = ShiftIntensity(self._offset) for key in self.keys: d[key] = shifter(d[key]) return d
[docs]class ScaleIntensityd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.ScaleIntensity`. Scale the intensity of input image to the given value range (minv, maxv). If `minv` and `maxv` not provided, use `factor` to scale image by ``v = v * (1 + factor)``. """ def __init__( self, keys: KeysCollection, minv: float = 0.0, maxv: float = 1.0, factor: Optional[float] = None ) -> None: """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` minv: minimum value of output data. maxv: maximum value of output data. factor: factor scale by ``v = v * (1 + factor)``. """ super().__init__(keys) self.scaler = ScaleIntensity(minv, maxv, factor)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.scaler(d[key]) return d
[docs]class RandScaleIntensityd(Randomizable, MapTransform): """ Dictionary-based version :py:class:`monai.transforms.RandScaleIntensity`. """ def __init__(self, keys: KeysCollection, factors: Union[Tuple[float, float], float], prob: float = 0.1): """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` factors: factor range to randomly scale by ``v = v * (1 + factor)``. if single number, factor value is picked from (-factors, factors). prob: probability of rotating. (Default 0.1, with 10% probability it returns a rotated array.) """ super().__init__(keys) self.factors = (-factors, factors) if not isinstance(factors, (list, tuple)) else factors assert len(self.factors) == 2, "factors should be a number or pair of numbers." self.prob = prob self._do_transform = False
[docs] def randomize(self) -> None: # type: ignore # see issue #495 self.factor = self.R.uniform(low=self.factors[0], high=self.factors[1]) self._do_transform = self.R.random() < self.prob
[docs] def __call__(self, data): d = dict(data) self.randomize() if not self._do_transform: return d scaler = ScaleIntensity(minv=None, maxv=None, factor=self.factor) for key in self.keys: d[key] = scaler(d[key]) return d
[docs]class NormalizeIntensityd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.NormalizeIntensity`. This transform can normalize only non-zero values or entire image, and can also calculate mean and std on each channel separately. Args: keys: keys of the corresponding items to be transformed. See also: monai.transforms.MapTransform subtrahend (ndarray): the amount to subtract by (usually the mean) divisor (ndarray): the amount to divide by (usually the standard deviation) nonzero: whether only normalize non-zero values. channel_wise: if using calculated mean and std, calculate on each channel separately or calculate on the entire image directly. """ def __init__( self, keys: KeysCollection, subtrahend: Optional[np.ndarray] = None, divisor: Optional[np.ndarray] = None, nonzero: bool = False, channel_wise: bool = False, ): super().__init__(keys) self.normalizer = NormalizeIntensity(subtrahend, divisor, nonzero, channel_wise)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.normalizer(d[key]) return d
[docs]class ThresholdIntensityd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.ThresholdIntensity`. Args: keys: keys of the corresponding items to be transformed. See also: monai.transforms.MapTransform threshold: the threshold to filter intensity values. above: filter values above the threshold or below the threshold, default is True. cval: value to fill the remaining parts of the image, default is 0. """ def __init__(self, keys: KeysCollection, threshold: float, above: bool = True, cval: float = 0.0) -> None: super().__init__(keys) self.filter = ThresholdIntensity(threshold, above, cval)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.filter(d[key]) return d
[docs]class ScaleIntensityRanged(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.ScaleIntensityRange`. Args: keys: keys of the corresponding items to be transformed. See also: monai.transforms.MapTransform a_min: intensity original range min. a_max: intensity original range max. b_min: intensity target range min. b_max: intensity target range max. clip: whether to perform clip after scaling. """ def __init__( self, keys: KeysCollection, a_min: float, a_max: float, b_min: float, b_max: float, clip: bool = False ) -> None: super().__init__(keys) self.scaler = ScaleIntensityRange(a_min, a_max, b_min, b_max, clip)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.scaler(d[key]) return d
[docs]class AdjustContrastd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.AdjustContrast`. Changes image intensity by gamma. Each pixel/voxel intensity is updated as: `x = ((x - min) / intensity_range) ^ gamma * intensity_range + min` Args: gamma: gamma value to adjust the contrast as function. """ def __init__(self, keys: KeysCollection, gamma: float): super().__init__(keys) self.adjuster = AdjustContrast(gamma)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.adjuster(d[key]) return d
[docs]class RandAdjustContrastd(Randomizable, MapTransform): """ Dictionary-based version :py:class:`monai.transforms.RandAdjustContrast`. Randomly changes image intensity by gamma. Each pixel/voxel intensity is updated as: `x = ((x - min) / intensity_range) ^ gamma * intensity_range + min` Args: keys: keys of the corresponding items to be transformed. See also: monai.transforms.MapTransform prob: Probability of adjustment. gamma (tuple of float or float): Range of gamma values. If single number, value is picked from (0.5, gamma), default is (0.5, 4.5). """ def __init__(self, keys: KeysCollection, prob: float = 0.1, gamma: Union[Tuple[float, float], float] = (0.5, 4.5)): super().__init__(keys) self.prob: float = prob self.gamma: Tuple[float, float] if not isinstance(gamma, (tuple, list)): assert gamma > 0.5, "if gamma is single number, must greater than 0.5 and value is picked from (0.5, gamma)" self.gamma = (0.5, gamma) else: assert len(gamma) == 2, "gamma should be a number or pair of numbers." self.gamma = gamma assert len(self.gamma) == 2, "gamma should be a number or pair of numbers." self._do_transform = False self.gamma_value = None
[docs] def randomize(self) -> None: # type: ignore # see issue #495 self._do_transform = self.R.random_sample() < self.prob self.gamma_value = self.R.uniform(low=self.gamma[0], high=self.gamma[1])
[docs] def __call__(self, data): d = dict(data) self.randomize() if not self._do_transform: return d adjuster = AdjustContrast(self.gamma_value) for key in self.keys: d[key] = adjuster(d[key]) return d
[docs]class ScaleIntensityRangePercentilesd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.ScaleIntensityRangePercentiles`. Args: keys: keys of the corresponding items to be transformed. See also: monai.transforms.MapTransform lower: lower percentile. upper: upper percentile. b_min: intensity target range min. b_max: intensity target range max. clip: whether to perform clip after scaling. relative: whether to scale to the corresponding percentiles of [b_min, b_max] """ def __init__( self, keys: KeysCollection, lower: float, upper: float, b_min: float, b_max: float, clip: bool = False, relative: bool = False, ) -> None: super().__init__(keys) self.scaler = ScaleIntensityRangePercentiles(lower, upper, b_min, b_max, clip, relative)
[docs] def __call__(self, data): d = dict(data) for key in self.keys: d[key] = self.scaler(d[key]) return d
RandGaussianNoiseD = RandGaussianNoiseDict = RandGaussianNoised ShiftIntensityD = ShiftIntensityDict = ShiftIntensityd RandShiftIntensityD = RandShiftIntensityDict = RandShiftIntensityd ScaleIntensityD = ScaleIntensityDict = ScaleIntensityd RandScaleIntensityD = RandScaleIntensityDict = RandScaleIntensityd NormalizeIntensityD = NormalizeIntensityDict = NormalizeIntensityd ThresholdIntensityD = ThresholdIntensityDict = ThresholdIntensityd ScaleIntensityRangeD = ScaleIntensityRangeDict = ScaleIntensityRanged AdjustContrastD = AdjustContrastDict = AdjustContrastd RandAdjustContrastD = RandAdjustContrastDict = RandAdjustContrastd ScaleIntensityRangePercentilesD = ScaleIntensityRangePercentilesDict = ScaleIntensityRangePercentilesd