Skip to content

Instantly share code, notes, and snippets.

@endolith
Last active December 13, 2023 18:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save endolith/123e4373e4e2dc8898617ec59e6ce830 to your computer and use it in GitHub Desktop.
Save endolith/123e4373e4e2dc8898617ec59e6ce830 to your computer and use it in GitHub Desktop.
Cyclic noise from filtering white noise in Python

This generates cyclic/repeating/perfect loop noise by low-pass filtering white noise in a cyclic way. Useful for "random" but looping animations, etc.:

This one loops in both space and time, for instance:

ezgif-5-bea77d8739ezgif-5-bea77d8739

Simplex noise typically has a more trapezoidal value distribution:

lmas/opensimplex#18 (comment)

which could be emulated by stretching the sample values.

Other examples:

[This code is a mess. TODO: Turn it into a def cyclic_noise function.]

import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage import gaussian_filter
rng = np.random.default_rng()
# shape = (1024, )
# shape = (512, 512)
shape = (128, 128, 128)
white = rng.normal(size=shape)
if len(shape) == 1:
fig, ax = plt.subplots(3, 1, sharex='col',
num='LPF noise comparison',
figsize=(9, 6))
else:
fig, ax = plt.subplots(1, 3,
num='LPF noise comparison',
figsize=(9, 6))
if white.ndim == 1:
# Plot the curve
ax[0].plot(white)
elif white.ndim == 2:
# Plot a heatmap
ax[0].imshow(white, cmap='gray')
elif white.ndim == 3:
# Plot a heatmap of the first slice
ax[0].imshow(white[0], cmap='gray')
ax[0].set_title('White noise')
filtered = gaussian_filter(white, 7, mode='wrap')
del white
# Plot it tiled next to itself
tiled = np.hstack((filtered, filtered))
if tiled.ndim == 1:
ax[1].plot(tiled)
elif tiled.ndim == 2:
ax[1].imshow(tiled, cmap='gray')
elif tiled.ndim == 3:
ax[1].imshow(tiled[0], cmap='gray')
ax[1].set_title('Filtered, tiled')
del tiled
vmin = filtered.min()
vmax = filtered.max()
if filtered.ndim == 3:
for n, slice in enumerate(filtered):
plt.imsave(f'slice {n:03d}.png', filtered[n], vmin=vmin, vmax=vmax,
cmap='gray')
@endolith
Copy link
Author

import numpy as np
from scipy.ndimage import gaussian_filter

def cyclic_noise(shape, sigma=7, rng)=None:
    """
shape stuff copy

sigmascalar or sequence of scalars

    Standard deviation for Gaussian kernel. The standard deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes.


copy rng stuff from scipy functions
    """
    white = rng.normal(size=shape)
    filtered = gaussian_filter(white, sigma, mode='wrap')
    return filtered

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment