|
|
|
|
|
import os, sys |
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
|
import numpy as np |
|
|
|
|
|
def interpolant(t): |
|
return t*t*t*(t*(t*6 - 15) + 10) |
|
|
|
|
|
def generate_perlin_noise_2d( |
|
shape, res, tileable=(False, False), interpolant=interpolant, percentile=None, |
|
): |
|
"""Generate a 2D numpy array of perlin noise. |
|
|
|
Args: |
|
shape: The shape of the generated array (tuple of two ints). |
|
This must be a multple of res. |
|
res: The number of periods of noise to generate along each |
|
axis (tuple of two ints). Note shape must be a multiple of |
|
res. |
|
tileable: If the noise should be tileable along each axis |
|
(tuple of two bools). Defaults to (False, False). |
|
interpolant: The interpolation function, defaults to |
|
t*t*t*(t*(t*6 - 15) + 10). |
|
|
|
Returns: |
|
A numpy array of shape shape with the generated noise. |
|
|
|
Raises: |
|
ValueError: If shape is not a multiple of res. |
|
""" |
|
delta = (res[0] / shape[0], res[1] / shape[1]) |
|
d = (shape[0] // res[0], shape[1] // res[1]) |
|
grid = np.mgrid[0:res[0]:delta[0], 0:res[1]:delta[1]]\ |
|
.transpose(1, 2, 0) % 1 |
|
|
|
angles = 2*np.pi*np.random.rand(res[0]+1, res[1]+1) |
|
gradients = np.dstack((np.cos(angles), np.sin(angles))) |
|
if tileable[0]: |
|
gradients[-1,:] = gradients[0,:] |
|
if tileable[1]: |
|
gradients[:,-1] = gradients[:,0] |
|
gradients = gradients.repeat(d[0], 0).repeat(d[1], 1) |
|
g00 = gradients[ :-d[0], :-d[1]] |
|
g10 = gradients[d[0]: , :-d[1]] |
|
g01 = gradients[ :-d[0],d[1]: ] |
|
g11 = gradients[d[0]: ,d[1]: ] |
|
|
|
n00 = np.sum(np.dstack((grid[:,:,0] , grid[:,:,1] )) * g00, 2) |
|
n10 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1] )) * g10, 2) |
|
n01 = np.sum(np.dstack((grid[:,:,0] , grid[:,:,1]-1)) * g01, 2) |
|
n11 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1]-1)) * g11, 2) |
|
|
|
t = interpolant(grid) |
|
n0 = n00*(1-t[:,:,0]) + t[:,:,0]*n10 |
|
n1 = n01*(1-t[:,:,0]) + t[:,:,0]*n11 |
|
|
|
noise = np.sqrt(2)*((1-t[:,:,1])*n0 + t[:,:,1]*n1) |
|
if percentile is None: |
|
return noise |
|
shres = np.percentile(noise, percentile) |
|
mask = np.zeros_like(noise) |
|
mask[noise >= shres] = 1. |
|
noise *= mask |
|
return noise, mask |
|
|
|
|
|
def generate_fractal_noise_2d( |
|
shape, res, octaves=1, persistence=0.5, |
|
lacunarity=2, tileable=(False, False), |
|
interpolant=interpolant, percentile=None |
|
): |
|
"""Generate a 2D numpy array of fractal noise. |
|
|
|
Args: |
|
shape: The shape of the generated array (tuple of two ints). |
|
This must be a multiple of lacunarity**(octaves-1)*res. |
|
res: The number of periods of noise to generate along each |
|
axis (tuple of two ints). Note shape must be a multiple of |
|
(lacunarity**(octaves-1)*res). |
|
octaves: The number of octaves in the noise. Defaults to 1. |
|
persistence: The scaling factor between two octaves. |
|
lacunarity: The frequency factor between two octaves. |
|
tileable: If the noise should be tileable along each axis |
|
(tuple of two bools). Defaults to (False, False). |
|
interpolant: The, interpolation function, defaults to |
|
t*t*t*(t*(t*6 - 15) + 10). |
|
|
|
Returns: |
|
A numpy array of fractal noise and of shape shape generated by |
|
combining several octaves of perlin noise. |
|
|
|
Raises: |
|
ValueError: If shape is not a multiple of |
|
(lacunarity**(octaves-1)*res). |
|
""" |
|
noise = np.zeros(shape) |
|
frequency = 1 |
|
amplitude = 1 |
|
for _ in range(octaves): |
|
noise += amplitude * generate_perlin_noise_2d( |
|
shape, (frequency*res[0], frequency*res[1]), tileable, interpolant |
|
) |
|
frequency *= lacunarity |
|
amplitude *= persistence |
|
if percentile is None: |
|
return noise |
|
shres = np.percentile(noise, percentile) |
|
mask = np.zeros_like(noise) |
|
mask[noise >= shres] = 1. |
|
noise *= mask |
|
return noise, mask |
|
|
|
|
|
|
|
|
|
|
|
def generate_fractal2d_batch(num, shape, res, octaves=5): |
|
noises = [] |
|
for i in range(num): |
|
noise, _ = generate_fractal_noise_2d(shape, res, octaves) |
|
noises.append(noise) |
|
idx = np.argmax(np.array(noises), axis = 0) |
|
return idx |
|
|
|
|
|
def generate_perlin2d_batch(num, shape, res): |
|
noises = [] |
|
for i in range(num): |
|
noise, _ = generate_perlin_noise_2d(shape, res) |
|
noises.append(noise) |
|
idx = np.argmax(np.array(noises), axis = 0) |
|
return idx |
|
|