Bases: IntensityTransform
Change image contrast by raising values to the power \(\gamma\).
The exponent is computed as \(\gamma = e^{\beta}\), where \(\beta\) is
sampled from the specified range. Positive \(\beta\) increases
contrast (gamma expansion), negative \(\beta\) decreases it (gamma
compression). See the
Gamma correction
Wikipedia entry for more information.
Note
Fractional exponentiation of negative values is not
well-defined for non-complex numbers. If negative values are
found in the input image \(I\), the applied transform is
\(\text{sign}(I) \cdot |I|^{\gamma}\) instead of the usual
\(I^{\gamma}\). Use Normalize to ensure
all values are positive if needed.
Parameters:
| Name |
Type |
Description |
Default |
log_gamma
|
float | tuple[float, float]
|
Range for \(\beta\) in \(\gamma = e^{\beta}\).
A scalar \(x\) means \(\beta = x\) (deterministic).
A 2-tuple \((a, b)\) means \(\beta \sim \mathcal{U}(a, b)\).
A Choice or Distribution may also be passed.
The default log_gamma=0 is a no-op (and warns).
|
0.0
|
**kwargs
|
Any
|
|
{}
|
Examples:
>>> import torchio as tio
>>> transform = tio.Gamma(log_gamma=0.5)
>>> transform = tio.Gamma(log_gamma=(-0.3, 0.3))
Source code in src/torchio/transforms/intensity/gamma.py
| class Gamma(IntensityTransform):
r"""Change image contrast by raising values to the power $\gamma$.
The exponent is computed as $\gamma = e^{\beta}$, where $\beta$ is
sampled from the specified range. Positive $\beta$ increases
contrast (gamma expansion), negative $\beta$ decreases it (gamma
compression). See the
[Gamma correction](https://en.wikipedia.org/wiki/Gamma_correction)
Wikipedia entry for more information.
Note:
Fractional exponentiation of negative values is not
well-defined for non-complex numbers. If negative values are
found in the input image $I$, the applied transform is
$\text{sign}(I) \cdot |I|^{\gamma}$ instead of the usual
$I^{\gamma}$. Use [`Normalize`][torchio.Normalize] to ensure
all values are positive if needed.
Args:
log_gamma: Range for $\beta$ in $\gamma = e^{\beta}$.
A scalar $x$ means $\beta = x$ (deterministic).
A 2-tuple $(a, b)$ means $\beta \sim \mathcal{U}(a, b)$.
A `Choice` or `Distribution` may also be passed.
The default `log_gamma=0` is a no-op (and warns).
**kwargs: See [`Transform`][torchio.Transform].
Examples:
>>> import torchio as tio
>>> transform = tio.Gamma(log_gamma=0.5)
>>> transform = tio.Gamma(log_gamma=(-0.3, 0.3))
"""
def __init__(
self,
*,
log_gamma: float | tuple[float, float] = 0.0,
**kwargs: Any,
) -> None:
super().__init__(**kwargs)
self.log_gamma = to_range(log_gamma)
self._warn_if_noop(
is_noop=self.log_gamma.is_constant(0.0),
hint="log_gamma=(-0.3, 0.3)",
)
def make_params(self, batch: SubjectsBatch) -> dict[str, Any]:
"""Sample the log-gamma value (per element when per-instance)."""
n = self._resolve_n(batch)
keep = self._keep_mask(batch, n)
log_gamma = self.log_gamma.sample_1d(n)
log_gamma = self._mask_identity(log_gamma, keep, identity=0.0)
params = {"log_gamma": self._serialize_param(log_gamma)}
self._tag_batched(params, batch, n, keep, ["log_gamma"])
return params
@property
def supports_per_instance_params(self) -> bool:
return True
@property
def supports_per_instance_p(self) -> bool:
return True
def apply_transform(
self,
batch: SubjectsBatch,
params: dict[str, Any],
) -> SubjectsBatch:
"""Raise each intensity image to the power gamma."""
log_gamma = params["log_gamma"]
for _name, img_batch in self._get_images(batch).items():
gamma = _gamma_from_log(log_gamma, img_batch.data)
data = img_batch.data
img_batch.data = data.sign() * data.abs().pow(gamma)
return batch
@property
def invertible(self) -> bool:
"""Whether this transform can be inverted."""
return True
def inverse(self, params: dict[str, Any]) -> _GammaInverse:
"""Invert by applying 1/gamma."""
return _GammaInverse(log_gamma=params["log_gamma"], copy=False)
|
invertible
property
Whether this transform can be inverted.
forward(data)
forward(data: Subject) -> Subject
forward(data: Image) -> Image
forward(data: Tensor) -> Tensor
forward(data: np.ndarray) -> np.ndarray
forward(data: sitk.Image) -> sitk.Image
forward(data: nib.Nifti1Image) -> nib.Nifti1Image
forward(data: dict) -> dict
forward(data: ImagesBatch) -> ImagesBatch
forward(data: SubjectsBatch) -> SubjectsBatch
Apply the transform.
The output type always matches the input type.
Parameters:
| Name |
Type |
Description |
Default |
data
|
Any
|
|
required
|
Source code in src/torchio/transforms/transform.py
| def forward(self, data: Any) -> Any:
"""Apply the transform.
The output type always matches the input type.
Args:
data: Input data to transform.
"""
return self._execute(data, params=None, sample_params=True)
|
apply_with_params(data, params)
apply_with_params(data: Subject, params: dict[str, Any]) -> Subject
apply_with_params(data: Image, params: dict[str, Any]) -> Image
apply_with_params(data: Tensor, params: dict[str, Any]) -> Tensor
apply_with_params(data: np.ndarray, params: dict[str, Any]) -> np.ndarray
apply_with_params(data: sitk.Image, params: dict[str, Any]) -> sitk.Image
apply_with_params(data: nib.Nifti1Image, params: dict[str, Any]) -> nib.Nifti1Image
apply_with_params(data: dict, params: dict[str, Any]) -> dict
apply_with_params(data: ImagesBatch, params: dict[str, Any]) -> ImagesBatch
apply_with_params(data: SubjectsBatch, params: dict[str, Any]) -> SubjectsBatch
Apply an exact parameter set without sampling.
This method bypasses the transform probability and
make_params(), but otherwise
follows the normal transform lifecycle: copy handling, input
wrapping, output-type restoration, and history recording.
Parameters:
| Name |
Type |
Description |
Default |
data
|
Any
|
|
required
|
params
|
dict[str, Any]
|
Exact parameters accepted by apply_transform.
|
required
|
Returns:
| Type |
Description |
Any
|
Transformed data with the same type as the input.
|
Raises:
| Type |
Description |
TypeError
|
If params is not a dictionary.
|
NotImplementedError
|
If the transform does not expose one
exact-parameter kernel.
|
ValueError
|
If per-instance parameter dimensions do not
match the input batch.
|
Source code in src/torchio/transforms/transform.py
| def apply_with_params(
self,
data: Any,
params: dict[str, Any],
) -> Any:
"""Apply an exact parameter set without sampling.
This method bypasses the transform probability and
[`make_params()`][torchio.Transform.make_params], but otherwise
follows the normal transform lifecycle: copy handling, input
wrapping, output-type restoration, and history recording.
Args:
data: Input data to transform.
params: Exact parameters accepted by `apply_transform`.
Returns:
Transformed data with the same type as the input.
Raises:
TypeError: If `params` is not a dictionary.
NotImplementedError: If the transform does not expose one
exact-parameter kernel.
ValueError: If per-instance parameter dimensions do not
match the input batch.
"""
if not self._supports_apply_with_params:
msg = (
f"{type(self).__name__}.apply_with_params() is not supported"
" because this transform does not expose a single"
" make_params/apply_transform parameter kernel."
)
raise NotImplementedError(msg)
if not isinstance(params, dict):
msg = f"Expected params to be a dict, got {type(params).__name__}"
raise TypeError(msg)
return self._execute(
data,
params=_copy.deepcopy(params),
sample_params=False,
)
|
to_hydra()
Export as a Hydra-compatible config dict.
Returns a dict with _target_ set to the fully qualified
class name and only non-default field values included.
Returns:
| Type |
Description |
dict[str, Any]
|
Dict suitable for hydra.utils.instantiate().
|
Source code in src/torchio/transforms/transform.py
| def to_hydra(self) -> dict[str, Any]:
"""Export as a Hydra-compatible config dict.
Returns a dict with `_target_` set to the fully qualified
class name and only non-default field values included.
Returns:
Dict suitable for `hydra.utils.instantiate()`.
"""
from .parameter_range import _ParameterRange
cls = type(self)
target = f"torchio.{cls.__qualname__}"
cfg: dict[str, Any] = {"_target_": target}
for name, default in _collect_init_params(cls).items():
value = getattr(self, name, default)
if isinstance(value, _ParameterRange):
if value._original == default:
continue
value = _hydra_value(value._original)
elif value == default:
continue
else:
value = _hydra_value(value)
cfg[name] = value
return cfg
|
make_params(batch)
Sample the log-gamma value (per element when per-instance).
Source code in src/torchio/transforms/intensity/gamma.py
| def make_params(self, batch: SubjectsBatch) -> dict[str, Any]:
"""Sample the log-gamma value (per element when per-instance)."""
n = self._resolve_n(batch)
keep = self._keep_mask(batch, n)
log_gamma = self.log_gamma.sample_1d(n)
log_gamma = self._mask_identity(log_gamma, keep, identity=0.0)
params = {"log_gamma": self._serialize_param(log_gamma)}
self._tag_batched(params, batch, n, keep, ["log_gamma"])
return params
|
Raise each intensity image to the power gamma.
Source code in src/torchio/transforms/intensity/gamma.py
| def apply_transform(
self,
batch: SubjectsBatch,
params: dict[str, Any],
) -> SubjectsBatch:
"""Raise each intensity image to the power gamma."""
log_gamma = params["log_gamma"]
for _name, img_batch in self._get_images(batch).items():
gamma = _gamma_from_log(log_gamma, img_batch.data)
data = img_batch.data
img_batch.data = data.sign() * data.abs().pow(gamma)
return batch
|
inverse(params)
Invert by applying 1/gamma.
Source code in src/torchio/transforms/intensity/gamma.py
| def inverse(self, params: dict[str, Any]) -> _GammaInverse:
"""Invert by applying 1/gamma."""
return _GammaInverse(log_gamma=params["log_gamma"], copy=False)
|