ahcore.transforms package#

Submodules#

ahcore.transforms.augmentations module#

Augmentations factory

class ahcore.transforms.augmentations.AugmentationFactory(data_description: DataDescription, data_module: LightningDataModule, initial_transforms: list[torch.nn.modules.module.Module] | None = None, random_apply_intensity: int | bool | ListConfig = False, random_apply_weights_intensity: list[float] | None = None, intensity_augmentations: list[kornia.augmentation._2d.intensity.base.IntensityAugmentationBase2D] | None = None, random_apply_geometric: int | bool | ListConfig = False, random_apply_weights_geometric: list[float] | ListConfig | None = None, geometric_augmentations: list[kornia.augmentation._2d.geometric.base.GeometricAugmentationBase2D] | None = None, final_transforms: list[torch.nn.modules.module.Module] | None = None)[source]#

Bases: Module

Factory for the augmentation. There are three classes of augmentations: - initial_transforms: Transforms which are the first to always be applied to the sample - intensity_augmentations: Transforms which only affect the intensity and not the geometry. Only applied to the image. - geometric_augmentations: Transforms which affect the geometry. They are applied to both the image, ROI and mask.

Initializes internal Module state, shared by both nn.Module and ScriptModule.

DATA_KEYS = {'image': DataKey.IMAGE, 'roi': DataKey.MASK, 'target': DataKey.MASK}#
forward(sample: dict[str, torch.Tensor]) dict[str, torch.Tensor][source]#

Defines the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

class ahcore.transforms.augmentations.CenterCrop(size: int | tuple[int, int], **kwargs: Any)[source]#

Bases: Module

Perform a center crop of the image and target

Initializes internal Module state, shared by both nn.Module and ScriptModule.

forward(*sample: Tensor, data_keys: list[str | int | kornia.constants.DataKey] | None = None, **kwargs: Any) list[torch.Tensor] | Tensor[source]#

Defines the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

class ahcore.transforms.augmentations.HEDColorAugmentation(scale_sigma: float | list[float] | ListConfig, bias_sigma: float | list[float] | ListConfig, epsilon: float = 1e-06, clamp_output_range: tuple[float, float] | None = (0, 1), p: float = 0.5, p_batch: float = 1.0, same_on_batch: bool = False, keepdim: bool = False, **kwargs: Any)[source]#

Bases: IntensityAugmentationBase2D

A torch implementation of the color stain augmentation algorithm on the deconvolved Hemaetoxylin-Eosin-DAB (HED) channels of an image as described by Tellez et al. (2018) in Appendix A & B here: https://arxiv.org/pdf/1808.05896.pdf.

Apply a color stain augmentation in the Hemaetoxylin-Eosin-DAB (HED) color space based on [1]. The fixed normalized OD matrix values are based on [2].

Parameters:
scale_sigma: float, ListConfig or list of floats

For each channel in the HED space a random scaling factor is drawn from alpha_i ~ U(1-sigma_i,1+sigma_i).

bias_sigma: float, ListConfig or list of floats

For each channel in the HED space a random bias is added drawn from beta_i ~ U(-sigma_i,sigma_i).

epsilon: float

Small positive bias to avoid numerical errors

clamp_output_range: tuple of floats or None

Clamp output in range after augmenting the input. Conventionally a range of [0, 1] is used, but this will discard some color information. scale_sigma and bias_sigma should be chosen carefully to prevent this.

NOTE: To reproduce augmentations as shown in [3], a larger positive bias of `epsilon=2` in combination with
`clamp_output_range=(0, 1)` should be used. Then, use `scale_sigma=bias_sigma=0.05` for `HED-light` and
`scale_sigma=bias_sigma=0.2` for `HED-strong`.
When using the default `epsilon=1e-6` and `clamp_output_range=(0, 1)`, this is not equal but comparable to
`scale_sigma=bias_sigma=0.15` for `HED-light` and `scale_sigma=bias_sigma=0.8` for `HED-strong`?

References

[1] Tellez, David, et al. “Whole-slide mitosis detection in H&E breast histology using PHH3 as

a reference to train distilled stain-invariant convolutional networks.” IEEE transactions on medical imaging 37.9 (2018): 2126-2136.

[2] Ruifrok AC, Johnston DA. Quantification of histochemical staining by color deconvolution.

Anal Quant Cytol Histol. 2001 Aug;23(4):291-9. PMID: 11531144.

[3] Tellez, David, et al. “Quantifying the effects of data augmentation and stain color normalization

in convolutional neural networks for computational pathology.” Medical image analysis 58 (2019): 101544.

HED_REFERENCE = tensor([[0.6500, 0.7000, 0.2900],         [0.0700, 0.9900, 0.1100],         [0.2700, 0.5700, 0.7800]])#
apply_transform(input: Tensor, params: dict[str, torch.Tensor], flags: dict[str, Any], transform: Tensor | None = None, **kwargs: Any) Tensor[source]#

Apply HED color augmentation on an input tensor.

class ahcore.transforms.augmentations.MeanStdNormalizer(mean: tuple[float, float, float] | None = None, std: tuple[float, float, float] | None = None)[source]#

Bases: Module

Normalizes the mean and standard deviation of the input image. Assumes the original range is [0, 255].

Parameters:
meantuple[float, float, float], optional
stdtuple[float, float, float], optional
forward(*args: Tensor, **kwargs: Any) list[torch.Tensor] | Tensor[source]#

Defines the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

ahcore.transforms.pre_transforms module#

Module for the pre-transforms, which are the transforms that are applied before samples are outputted in a dataset.

class ahcore.transforms.pre_transforms.AllowCollate[source]#

Bases: object

Path objects cannot be collated in the standard pytorch collate function. This transform converts the path to a string. Same holds for the annotations and labels

class ahcore.transforms.pre_transforms.ImageToTensor[source]#

Bases: object

Transform to translate the output of a dlup dataset to data_description supported by AhCore

class ahcore.transforms.pre_transforms.LabelToClassIndex(index_map: dict[str, int])[source]#

Bases: object

Maps label values to class indices according to the index_map specified in the data description. Example:

If there are two tasks:
  • Task1 with classes {A, B, C}

  • Task2 with classes {X, Y}

Then an input sample could look like: {{“labels”: {“Task1”: “C”, “Task2: “Y”}, …} If the index map is: {“A”: 0, “B”: 1, “C”: 2, “X”: 0, “Y”: 1} The returned sample will look like: {“labels”: {“task1”: 2, “task2”: 1}, …}

class ahcore.transforms.pre_transforms.OneHotEncodeMask(index_map: dict[str, int])[source]#

Bases: object

Create the one-hot encoding of the mask for segmentation. If we have N classes, the result will be an (B, N + 1, H, W) tensor, where the first sample is the background. Parameters ———- index_map : dict[str, int]

Index map mapping the label name to the integer value it has in the mask.

class ahcore.transforms.pre_transforms.PreTransformTaskFactory(transforms: list[Callable[[Any], Any]])[source]#

Bases: object

Pre-transforms are transforms that are applied to the samples directly originating from the dataset. These transforms are typically the same for the specific tasks (e.g., segmentation, detection or whole-slide classification). Each of these tasks has a specific constructor. In all cases, the final transforms convert the PIL image (as the image key of the output sample) to a tensor, and ensure that the sample dictionary can be collated. In ahcore, the augmentations are done separately and are part of the model in the forward function.

Parameters:
transformslist

List of transforms to be used.

classmethod for_segmentation(data_description: DataDescription, requires_target: bool = True) PreTransformTaskFactory[source]#

Pre-transforms for segmentation tasks. If the target is required these transforms are applied as follows: - Labels are renamed (for instance if you wish to map several labels to on specific class) - Polygon and Point annotations are converted to a mask - The mask is one-hot encoded.

Parameters:
data_descriptionDataDescription
requires_targetbool
Returns:
PreTransformTaskFactory

The PreTransformTaskFactory initialized for segmentation tasks.

classmethod for_tile_classification(roi_name: str, label: str, threshold: float) PreTransformTaskFactory[source]#

Tile classification is based on a transform which checks if a polygon is present for a given threshold

classmethod for_wsi_classification(data_description: DataDescription, requires_target: bool = True) PreTransformTaskFactory[source]#
ahcore.transforms.pre_transforms.one_hot_encoding(index_map: dict[str, int], mask: ndarray[Any, dtype[int64 | float64]]) ndarray[Any, dtype[float32]][source]#

functional interface to convert labels/predictions into one-hot codes

Parameters:
index_mapdict[str, int]

Index map mapping the label name to the integer value it has in the mask.

mask: npt.NDArray

The numpy array of model predictions or ground truth labels.

Returns:
new_mask: npt.NDArray

One-hot encoded output

Module contents#

All transformations. These include: - Augmentations: these are nn.Modules, and can be part of the model - Pre-transforms: these are transforms that are applied to samples directly out of the dataset. E.g., convert a polygon to a mask