fractal_noise#
This function wraps the pyfastnoisesimd package. The PoreSpy wrapper offers a slightly simpler experience which is more consistent with the function-based approach found in PoreSpy, scikit-image, and scipy.ndimage. For full control over its features you can use it directly. This optional package is not installed with PoreSpy by default.
The documentation environment pins the upstream pyfastnoisesimd v0.4.3 source release, which supports NumPy 2; the PyPI v0.4.2 release still uses the removed numpy.product alias. To run this notebook from a PoreSpy source checkout, install the documentation environment with uv sync --group docs --group interactive and use its Python kernel. Building this dependency requires a C++ compiler; the project configuration supplies NumPy headers in the isolated build environment.
import matplotlib.pyplot as plt
import porespy as ps
import numpy as np
np.random.seed(10)
shape = [200, 200]
im = ps.generators.fractal_noise(shape=shape)
fig, ax = plt.subplots(1, 1, figsize=[4, 4])
ax.imshow(im, origin="lower", interpolation="none")
ax.axis(False);
cores#
The noise is generated by the pyfastnoisesimd package which supports multiple cores to really speed things up. By default we use all the available cores on the machine, however, occasionally this causes problems and kernel crashes. Setting this argument to a value less than the maximum usually avoids these issues. Here we’ll use 1.
cores = 1
im = ps.generators.fractal_noise(shape=shape, cores=cores)
fig, ax = plt.subplots(1, 1, figsize=[4, 4])
ax.imshow(im, origin="lower", interpolation="none")
ax.axis(False);
seed#
In order to produce the same image twice it’s possible send a seed value to the function. Unfortunately the numpy.random.seed function is not recognized:
seed = 0
im1 = ps.generators.fractal_noise(shape=shape, seed=seed, cores=cores)
im2 = ps.generators.fractal_noise(shape=shape, seed=seed, cores=cores)
seed = 1
im3 = ps.generators.fractal_noise(shape=shape, seed=seed, cores=cores)
fig, ax = plt.subplots(1, 3, figsize=[9, 3])
ax[0].imshow(im1, origin="lower", interpolation="none")
ax[1].imshow(im2, origin="lower", interpolation="none")
ax[2].imshow(im3, origin="lower", interpolation="none")
ax[0].axis(False)
ax[1].axis(False)
ax[2].axis(False)
ax[0].set_title("seed = 0")
ax[1].set_title("seed = 0")
ax[2].set_title("seed = 1");
frequency#
This controls the size of the blobs relative to the image size, with larger values giving smaller features:
fig, ax = plt.subplots(1, 2, figsize=[8, 4])
frequency = 0.1
im1 = ps.generators.fractal_noise(shape=shape, frequency=frequency, cores=cores, seed=seed)
ax[0].imshow(im)
ax[0].axis(False)
ax[0].set_title(f"frequency = 0.05")
frequency = 0.05
im2 = ps.generators.fractal_noise(shape=shape, frequency=frequency, cores=cores, seed=seed)
ax[1].imshow(im2)
ax[1].axis(False)
ax[1].set_title(f"frequency = 0.1");
octaves#
The numbers of octaves controls the levels of noise that get overlaid to create the realistic texture
fig, ax = plt.subplots(1, 2, figsize=[8, 4])
octaves = 2
im1 = ps.generators.fractal_noise(
shape=shape, octaves=octaves, frequency=frequency, seed=seed, cores=cores
)
ax[0].imshow(im1)
ax[0].axis(False)
ax[0].set_title(f"octaves = {octaves}")
octaves = 10
im2 = ps.generators.fractal_noise(
shape=shape, octaves=octaves, frequency=frequency, seed=seed, cores=cores
)
ax[1].imshow(im2)
ax[1].axis(False)
ax[1].set_title(f"octaves = {octaves}");
gain#
This controls the intensity of each added layer of noise:
fig, ax = plt.subplots(1, 2, figsize=[8, 4])
gain = 0.8
im1 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores)
ax[0].imshow(im1)
ax[0].axis(False)
ax[0].set_title(f"gain = {gain}")
gain = 0.5
im2 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores)
ax[1].imshow(im2)
ax[1].axis(False)
ax[1].set_title(f"gain = {gain}");
mode#
The pyfastnoisesimd package provides 4 different methods for computing noise, which we expose via the mode argument:
fig, ax = plt.subplots(2, 2, figsize=[8, 8])
mode = "perlin"
im1 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores, mode=mode)
ax[0][0].imshow(im1)
ax[0][0].axis(False)
ax[0][0].set_title(f"mode = {mode}")
mode = "simplex"
im2 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores, mode=mode)
ax[0][1].imshow(im2)
ax[0][1].axis(False)
ax[0][1].set_title(f"mode = {mode}")
mode = "cubic"
im2 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores, mode=mode)
ax[1][0].imshow(im2)
ax[1][0].axis(False)
ax[1][0].set_title(f"mode = {mode}")
mode = "value"
im2 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores, mode=mode)
ax[1][1].imshow(im2)
ax[1][1].axis(False)
ax[1][1].set_title(f"mode = {mode}");
uniform and porosity#
uniform Controls whether the returned noise values are scaled to a uniform distribution, which is useful for thresholding to create a specific porosity, or if the original distribution is returned.
fig, ax = plt.subplots(2, 2, figsize=[8, 8])
mode = "perlin"
uniform = True
im1 = ps.generators.fractal_noise(
shape=shape, gain=gain, seed=seed, cores=cores, mode=mode, uniform=uniform
)
ax[0][0].imshow(im1)
ax[0][0].axis(False)
ax[0][0].set_title(f"uniform = {uniform}")
uniform = False
im2 = ps.generators.fractal_noise(
shape=shape, gain=gain, seed=seed, cores=cores, mode=mode, uniform=uniform
)
ax[0][1].imshow(im2)
ax[0][1].axis(False)
ax[0][1].set_title(f"uniform = {uniform}")
ax[1][0].hist(im1.flatten())
ax[1][1].hist(im2.flatten());
porosity can be specified for a specific porosity level. The image is thresholded after being converted into a uniform distribution. In this case, uniform does not need to be specified to True.
fig, ax = plt.subplots(1, 2, figsize=[8, 4])
porosity1 = 0.3
im1 = ps.generators.fractal_noise(
shape=shape, porosity=porosity1, gain=gain, seed=seed, cores=cores, mode=mode
)
ax[0].imshow(im1)
ax[0].axis(False)
ax[0].set_title(f"porosity = {porosity1}")
porosity2 = 0.6
im2 = ps.generators.fractal_noise(
shape=shape, porosity=porosity2, gain=gain, seed=seed, cores=cores, mode=mode
)
ax[1].imshow(im2)
ax[1].axis(False)
ax[1].set_title(f"porosity = {porosity2}");