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 it’s features you can just use it directly since it is installed with PoreSpy.

import matplotlib.pyplot as plt
import porespy as ps
import numpy as np
import inspect
inspect.signature(ps.generators.fractal_noise)
<Signature (shape, frequency=0.05, octaves=4, gain=0.5, mode='simplex', seed=None, cores=None, uniform=True)>
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);
../../../_images/8f5d7a0c0f7369afb316979ee2e4f0cf21761c3e0f85fdbf5ada92e001ca19a6.png

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);
../../../_images/6021e02e34ea3177cc75a836827884dfa67cf5c489cff724aec59d2e51d12829.png

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');
../../../_images/6d0a923a0c7dbef7000c063e1d2fae9206c98494647c07f26be573a2ea20aca6.png

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');
../../../_images/817397f646dfca7dd9dc3019c23b09d47d4bd3f62914c2a63a13b6071991c441.png

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}');
../../../_images/7241a9432beed4f9d4473b377e3ecd9e8511e675b5e5f933a9102f2f6bfd4171.png

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}');
../../../_images/c0e8eec9b8771d3f29d57219265ba7ca084eb588b59583c5548975032e9312fe.png

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}');
../../../_images/156609a31f1cf7375a4fa03355c12d5eb1755840a3ba1f2cfa04f73c54351277.png

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());
../../../_images/5f8dcf0a2a9b13751eb13debe318e2e03c7b5f923afb49e3753b74785ba8111c.png
fig, ax = plt.subplots(1, 2, figsize=[8, 4])

uniform=True
im1 = ps.generators.fractal_noise(shape=shape, gain=gain, seed=seed, cores=cores, mode=mode, uniform=uniform)

porosity=0.3
ax[0].imshow(im1 < porosity)
ax[0].axis(False)
ax[0].set_title(f'porosity = {porosity}')

porosity=0.6
ax[1].imshow(im1 < porosity)
ax[1].axis(False)
ax[1].set_title(f'porosity = {porosity}');
../../../_images/be4b78111cbbd7b79ab3038c741bceababb80d0e4446df4545dd82b60747bb28.png