from typing import Tuple
import cv2
import numpy as np
from noise import pnoise2
from perlin_numpy import generate_fractal_noise_3d, generate_perlin_noise_3d
from event_aug.utils import imgs_to_video
[docs]def shift_range(arr: np.ndarray):
"""
Shift the range of values in an array to [0, 255]
Parameters
----------
arr: np.ndarray
Input array
Returns
-------
np.ndarray
Array with shifted range
"""
max_arr = np.max(arr)
min_arr = np.min(arr)
arr = (arr - min_arr) / (max_arr - min_arr)
arr = arr * 255
return arr
[docs]def downsample(
arr: np.ndarray, reshape_size: Tuple[int, int], crop_size: Tuple[int, int] = None
) -> np.ndarray:
"""
Downsample an array along the spatial dimensions to a given size by either resizing or cropping or both.
Parameters
----------
arr: np.ndarray
Input array.
reshape_size: Tuple[int, int]
Size to reshape the array along spatial dimensions to using interpolation.
crop_size: Tuple[int, int]
Size to crop the array along spatial dimensions to.
Returns
-------
np.ndarray
Downsampled array.
"""
if reshape_size is not None:
assert len(arr.shape) in (
2,
3,
4,
), "Input array must be a single-channel / multi-channel image or video."
if len(arr.shape) == 2:
arr = cv2.resize(arr, reshape_size)
elif len(arr.shape) == 3 and arr.shape[2] in (1, 3):
arr = cv2.resize(arr, reshape_size)
else:
resized_arrs = []
for i in range(arr.shape[0]):
resized_arrs.append(cv2.resize(arr[i], reshape_size))
arr = np.array(resized_arrs)
if crop_size is not None:
arr = arr[..., : crop_size[0], : crop_size[1]]
return arr
[docs]def postprocess_3d_noise(arr, reshape_size=None, crop_size=None):
arr = downsample(arr, reshape_size, crop_size)
arr = shift_range(arr)
return arr
[docs]def gen_perlin_2d(
shape: Tuple[int, int],
scale: int = 100,
octaves: int = 6,
persistence: float = 0.5,
lacunarity: float = 2.0,
seed: int = 0,
save_path: str = None,
reshape_size: Tuple[int, int] = None,
crop_size: Tuple[int, int] = None,
) -> np.ndarray:
"""
Generates 2D Perlin noise.
Parameters
----------
shape: Tuple[int, int]
Shape of the 2D output array.
scale: int
Scale of the noise.
octaves: int
Number of octaves to use.
persistence: float
Scaling factor between two octaves.
lacunarity: float
Frequency factor between two octaves.
seed: int
Seed for the noise generation.
save_path: str
Path to save the generated noise as an image.
reshape_size: Tuple[int, int]
Size to reshape the array along spatial dimensions to using interpolation.
crop_size: Tuple[int, int]
Size to crop the array along spatial dimensions to.
Returns
-------
np.ndarray
2D array of Perlin noise.
"""
if not seed:
seed = np.random.randint(0, 100)
arr = np.zeros(shape)
for i in range(shape[0]):
for j in range(shape[1]):
arr[i][j] = pnoise2(
i / scale,
j / scale,
octaves=octaves,
persistence=persistence,
lacunarity=lacunarity,
repeatx=1024,
repeaty=1024,
base=seed,
)
arr = shift_range(arr)
arr = downsample(arr, reshape_size, crop_size)
if save_path is not None:
cv2.imwrite(save_path, arr * 255)
return arr
[docs]def gen_perlin_3d(
shape: Tuple[int, int, int],
res: Tuple[int, int, int] = (1, 4, 4),
tileable: Tuple[bool, bool, bool] = (True, False, False),
reshape_size: Tuple[int, int] = None,
crop_size: Tuple[int, int] = None,
return_arr: bool = True,
save_arr: bool = False,
arr_save_path: str = None,
save_video: bool = False,
video_save_path: str = None,
out_fps: int = 25,
) -> np.ndarray:
"""
Generates 3D Perlin noise.
Parameters
----------
shape: Tuple[int, int, int]
Shape of the 3D Perlin noise wanted. This must be a multiple of res.
res: Tuple[int, int, int]
The number of periods of noise to generate along each
axis (tuple of three ints). Note that shape must be a multiple of res.
tileable: Tuple[bool, bool, bool]
If the noise should be tileable along each axis.
reshape_size: Tuple[int, int]
Size to reshape the array along spatial dimensions to using interpolation.
crop_size: Tuple[int, int]
Size to crop the array along spatial dimensions to.
return_arr: bool
If the noise array should be returned.
save_arr: bool
If the generated array should be saved to an npy file.
arr_save_path: str
Path (.npy) to save the generated array to.
save_video: bool
If the generated array should be saved as a video to a .mp4 file.
video_save_path: str
Path (.mp4) to save the generated array as a video to.
out_fps: int
FPS of the output video.
Returns
-------
np.ndarray
3D array of Perlin noise.
"""
noise = generate_perlin_noise_3d(shape, res, tileable)
noise = postprocess_3d_noise(noise, reshape_size, crop_size)
if save_arr:
assert arr_save_path is not None
assert arr_save_path.endswith(".npy")
np.save(arr_save_path, noise)
if save_video:
assert video_save_path is not None
assert video_save_path.endswith(".mp4")
imgs_to_video(video_save_path, img_arr=noise, out_fps=out_fps)
if return_arr:
return noise
return None
[docs]def gen_fractal_3d(
shape: Tuple[int, int, int],
res: Tuple[int, int, int] = (1, 4, 4),
tileable: Tuple[bool, bool, bool] = (True, False, False),
octaves: int = 1,
persistence: float = 0.5,
lacunarity: int = 2,
reshape_size: Tuple[int, int] = None,
crop_size: Tuple[int, int] = None,
return_arr: bool = True,
save_arr: bool = False,
arr_save_path: str = None,
save_video: bool = False,
video_save_path: str = None,
out_fps: int = 25,
) -> np.ndarray:
"""
Generates 3D Fractal noise.
Parameters
----------
shape: Tuple[int, int, int]
Shape of the 3D fractal noise wanted. This must be a multiple of lacunarity**(octaves-1)*res.
res: Tuple[int, int, int]
The number of periods of noise to generate along each
axis (tuple of three ints). Note that shape must be a multiple of
(lacunarity**(octaves-1)*res).
tileable: Tuple[bool, bool, bool]
If the noise should be tileable along each axis.
octaves: int
Number of octaves in the noise.
persistence: float
The scaling factor between two octaves.
lacunarity: int
The frequency factor between two octaves.
reshape_size: Tuple[int, int]
Size to reshape the array along spatial dimensions to using interpolation.
crop_size: Tuple[int, int]
Size to crop the array along spatial dimensions to.
return_arr: bool
If the noise array should be returned.
save_arr: bool
If the generated array should be saved to an npy file.
arr_save_path: str
Path (.npy) to save the generated array to.
save_video: bool
If the generated array should be saved as a video to a .mp4 file.
video_save_path: str
Path (.mp4) to save the generated array as a video to.
out_fps: int
FPS of the output video.
Returns
-------
np.ndarray
3D array of Fractal noise.
"""
noise = generate_fractal_noise_3d(
shape, res, octaves, persistence, lacunarity, tileable
)
noise = postprocess_3d_noise(noise, reshape_size, crop_size)
if save_arr:
assert arr_save_path is not None
assert arr_save_path.endswith(".npy")
np.save(arr_save_path, noise)
if save_video:
assert video_save_path is not None
assert video_save_path.endswith(".mp4")
imgs_to_video(video_save_path, img_arr=noise, out_fps=out_fps)
if return_arr:
return noise
return None