diff --git a/anomalib/data/utils/__init__.py b/anomalib/data/utils/__init__.py index 45c94c587f..f65a97fa9d 100644 --- a/anomalib/data/utils/__init__.py +++ b/anomalib/data/utils/__init__.py @@ -15,6 +15,7 @@ # and limitations under the License. from .download import DownloadProgressBar, hash_check +from .generators import random_2d_perlin from .image import get_image_filenames, read_image -__all__ = ["get_image_filenames", "hash_check", "read_image", "DownloadProgressBar"] +__all__ = ["get_image_filenames", "hash_check", "random_2d_perlin", "read_image", "DownloadProgressBar"] diff --git a/anomalib/data/utils/generators/__init__.py b/anomalib/data/utils/generators/__init__.py new file mode 100644 index 0000000000..a79bad9770 --- /dev/null +++ b/anomalib/data/utils/generators/__init__.py @@ -0,0 +1,8 @@ +"""Utilities to generate synthetic data.""" + +# Copyright (C) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +from .perlin import random_2d_perlin + +__all__ = ["random_2d_perlin"] diff --git a/anomalib/models/draem/utils/perlin.py b/anomalib/data/utils/generators/perlin.py similarity index 79% rename from anomalib/models/draem/utils/perlin.py rename to anomalib/data/utils/generators/perlin.py index 0c7a72f394..760222fa44 100644 --- a/anomalib/models/draem/utils/perlin.py +++ b/anomalib/data/utils/generators/perlin.py @@ -12,9 +12,11 @@ # pylint: disable=invalid-name import math +from typing import Tuple, Union import numpy as np import torch +from torch import Tensor def lerp_np(x, y, w): @@ -63,7 +65,32 @@ def f(t): return np.sqrt(2) * ((1 - t[:, :, 1]) * n0 + t[:, :, 1] * n1) -def rand_perlin_2d_np(shape, res, fade=lambda t: 6 * t**5 - 15 * t**4 + 10 * t**3): +def random_2d_perlin( + shape: Tuple, + res: Tuple[Union[int, Tensor], Union[int, Tensor]], + fade=lambda t: 6 * t**5 - 15 * t**4 + 10 * t**3, +) -> Union[np.ndarray, Tensor]: + """Returns a random 2d perlin noise array. + + Args: + shape (Tuple): Shape of the 2d map. + res (Tuple[Union[int, Tensor]]): Tuple of scales for perlin noise for height and width dimension. + fade (_type_, optional): Function used for fading the resulting 2d map. + Defaults to equation 6*t**5-15*t**4+10*t**3. + + Returns: + Union[np.ndarray, Tensor]: Random 2d-array/tensor generated using perlin noise. + """ + if isinstance(res[0], int): + result = _rand_perlin_2d_np(shape, res, fade) + elif isinstance(res[0], Tensor): + result = _rand_perlin_2d(shape, res, fade) + else: + raise TypeError(f"got scales of type {type(res[0])}") + return result + + +def _rand_perlin_2d_np(shape, res, fade=lambda t: 6 * t**5 - 15 * t**4 + 10 * t**3): """Generate a random image containing Perlin noise. Numpy version.""" delta = (res[0] / shape[0], res[1] / shape[1]) d = (shape[0] // res[0], shape[1] // res[1]) @@ -89,7 +116,7 @@ def dot(grad, shift): return math.sqrt(2) * lerp_np(lerp_np(n00, n10, t[..., 0]), lerp_np(n01, n11, t[..., 0]), t[..., 1]) -def rand_perlin_2d(shape, res, fade=lambda t: 6 * t**5 - 15 * t**4 + 10 * t**3): +def _rand_perlin_2d(shape, res, fade=lambda t: 6 * t**5 - 15 * t**4 + 10 * t**3): """Generate a random image containing Perlin noise. PyTorch version.""" delta = (res[0] / shape[0], res[1] / shape[1]) d = (shape[0] // res[0], shape[1] // res[1]) @@ -128,7 +155,7 @@ def rand_perlin_2d_octaves(shape, res, octaves=1, persistence=0.5): frequency = 1 amplitude = 1 for _ in range(octaves): - noise += amplitude * rand_perlin_2d(shape, (frequency * res[0], frequency * res[1])) + noise += amplitude * _rand_perlin_2d(shape, (frequency * res[0], frequency * res[1])) frequency *= 2 amplitude *= persistence return noise diff --git a/anomalib/models/draem/utils/augmenter.py b/anomalib/models/draem/utils/augmenter.py index 7ae49c1315..2f3e487d20 100644 --- a/anomalib/models/draem/utils/augmenter.py +++ b/anomalib/models/draem/utils/augmenter.py @@ -21,7 +21,7 @@ from torch import Tensor from torchvision.datasets.folder import IMG_EXTENSIONS -from anomalib.models.draem.utils.perlin import rand_perlin_2d_np +from anomalib.data.utils import random_2d_perlin class Augmenter: @@ -84,7 +84,7 @@ def generate_perturbation( perlin_scalex = 2 ** random.randint(min_perlin_scale, perlin_scale) perlin_scaley = 2 ** random.randint(min_perlin_scale, perlin_scale) - perlin_noise = rand_perlin_2d_np((height, width), (perlin_scalex, perlin_scaley)) + perlin_noise = random_2d_perlin((height, width), (perlin_scalex, perlin_scaley)) perlin_noise = self.rot(image=perlin_noise) # Create mask from perlin noise