Example #1
0
def blobs(shape: List[int], porosity: float = 0.5, blobiness: int = 1,
          **kwargs):
    """
    Generates an image containing amorphous blobs

    Parameters
    ----------
    shape : list
        The size of the image to generate in [Nx, Ny, Nz] where N is the
        number of voxels

    porosity : float
        If specified, this will threshold the image to the specified value
        prior to returning.  If ``None`` is specified, then the scalar noise
        field is converted to a uniform distribution and returned without
        thresholding.

    blobiness : int or list of ints(default = 1)
        Controls the morphology of the blobs.  A higher number results in
        a larger number of small blobs.  If a list is supplied then the blobs
        are anisotropic.

    Returns
    -------
    image : ND-array
        A boolean array with ``True`` values denoting the pore space

    See Also
    --------
    norm_to_uniform

    """
    blobiness = np.array(blobiness)
    shape = np.array(shape)
    parallel = kwargs.pop('parallel', False)
    divs = kwargs.pop('divs', 2)
    cores = kwargs.pop('cores', None)
    if np.size(shape) == 1:
        shape = np.full((3, ), int(shape))
    sigma = np.mean(shape)/(40*blobiness)
    im = np.random.random(shape)
    if parallel:
        # TODO: The determination of the overlap should be done rigorously
        im = ps.filters.chunked_func(func=spim.gaussian_filter,
                                     input=im, sigma=sigma,
                                     divs=divs, cores=cores, overlap=10)
    else:
        im = spim.gaussian_filter(im, sigma=sigma)
    im = norm_to_uniform(im, scale=[0, 1])
    if porosity:
        im = im < porosity
    return im
Example #2
0
def generate_phantom(shape, porosity, sigma, noise=0):
    """
    noise=0 - бинарный исходный фантом
    
    noise>0 - есть зашумление (рекомендую noise = 0.1)
    """
    shape = np.array(shape)
    if np.size(shape) == 1:
        shape = np.full((3, ), int(shape))
    img = np.random.random(shape)
    img = gaussian_filter(img, sigma=sigma)
    img = norm_to_uniform(img, scale=[0, 1])
    if porosity:
        img = img > porosity

    img = sp_noise(img, noise).astype(bool)
    return img
Example #3
0
def blobs(shape: List[int], porosity: float = 0.5, blobiness: int = 1):
    """
    Generates an image containing amorphous blobs

    Parameters
    ----------
    shape : list
        The size of the image to generate in [Nx, Ny, Nz] where N is the
        number of voxels

    porosity : float
        If specified, this will threshold the image to the specified value
        prior to returning.  If ``None`` is specified, then the scalar noise
        field is converted to a uniform distribution and returned without
        thresholding.

    blobiness : int or list of ints(default = 1)
        Controls the morphology of the blobs.  A higher number results in
        a larger number of small blobs.  If a list is supplied then the blobs
        are anisotropic.

    Returns
    -------
    image : ND-array
        A boolean array with ``True`` values denoting the pore space

    See Also
    --------
    norm_to_uniform

    """
    blobiness = sp.array(blobiness)
    shape = sp.array(shape)
    if sp.size(shape) == 1:
        shape = sp.full((3, ), int(shape))
    sigma = sp.mean(shape)/(40*blobiness)
    im = sp.random.random(shape)
    im = spim.gaussian_filter(im, sigma=sigma)
    im = norm_to_uniform(im, scale=[0, 1])
    if porosity:
        im = im < porosity
    return im
Example #4
0
def blobs(shape: List[int], porosity: float = 0.5, blobiness: int = 1):
    """
    Generates an image containing amorphous blobs

    Parameters
    ----------
    shape : list
        The size of the image to generate in [Nx, Ny, Nz] where N is the
        number of voxels

    porosity : float
        If specified, this will threshold the image to the specified value
        prior to returning.  If no value is given (the default), then the
        scalar noise field is returned.

    blobiness : array_like (default = 1)
        Controls the morphology of the blobs.  A higher number results in
        a larger number of small blobs.  If a vector is supplied then the blobs
        are anisotropic.

    Returns
    -------
    If porosity is given, then a boolean array with ``True`` values denoting
    the pore space is returned.  If not, then normally distributed and
    spatially correlated randomly noise is returned.

    See Also
    --------
    norm_to_uniform

    """
    blobiness = sp.array(blobiness)
    shape = sp.array(shape)
    if sp.size(shape) == 1:
        shape = sp.full((3, ), int(shape))
    sigma = sp.mean(shape) / (40 * blobiness)
    im = sp.random.random(shape)
    im = spim.gaussian_filter(im, sigma=sigma)
    if porosity:
        im = norm_to_uniform(im, scale=[0, 1])
        im = im < porosity
    return im
Example #5
0
def generate_noise(shape: List[int], porosity=None, octaves: int = 3,
                   frequency: int = 32, mode: str = 'simplex'):
    r"""
    Generate a field of spatially correlated random noise using the Perlin
    noise algorithm, or the updated Simplex noise algorithm.

    Parameters
    ----------
    shape : array_like
        The size of the image to generate in [Nx, Ny, Nz] where N is the
        number of voxels.

    porosity : float
        If specified, this will threshold the image to the specified value
        prior to returning.  If no value is given (the default), then the
        scalar noise field is returned.

    octaves : int
        Controls the *texture* of the noise, with higher octaves giving more
        complex features over larger length scales.

    frequency : array_like
        Controls the relative sizes of the features, with higher frequencies
        giving larger features.  A scalar value will apply the same frequency
        in all directions, given an isotropic field; a vector value will
        apply the specified values along each axis to create anisotropy.

    mode : string
        Which noise algorithm to use, either ``'simplex'`` (default) or
        ``'perlin'``.

    Returns
    -------
    image : ND-array
        If porosity is given, then a boolean array with ``True`` values
        denoting the pore space is returned.  If not, then normally
        distributed and spatially correlated randomly noise is returned.

    Notes
    -----
    This method depends the a package called 'noise' which must be
    compiled. It is included in the Anaconda distribution, or a platform
    specific binary can be downloaded.

    See Also
    --------
    porespy.tools.norm_to_uniform

    """
    try:
        import noise
    except ModuleNotFoundError:
        raise Exception("The noise package must be installed")
    shape = sp.array(shape)
    if sp.size(shape) == 1:
        Lx, Ly, Lz = sp.full((3, ), int(shape))
    elif len(shape) == 2:
        Lx, Ly = shape
        Lz = 1
    elif len(shape) == 3:
        Lx, Ly, Lz = shape
    if mode == 'simplex':
        f = noise.snoise3
    else:
        f = noise.pnoise3
    frequency = sp.atleast_1d(frequency)
    if frequency.size == 1:
        freq = sp.full(shape=[3, ], fill_value=frequency[0])
    elif frequency.size == 2:
        freq = sp.concatenate((frequency, [1]))
    else:
        freq = sp.array(frequency)
    im = sp.zeros(shape=[Lx, Ly, Lz], dtype=float)
    for x in range(Lx):
        for y in range(Ly):
            for z in range(Lz):
                im[x, y, z] = f(x=x/freq[0], y=y/freq[1], z=z/freq[2],
                                octaves=octaves)
    im = im.squeeze()
    if porosity:
        im = norm_to_uniform(im, scale=[0, 1])
        im = im < porosity
    return im
Example #6
0
def perlin_noise(shape: List[int], porosity=None, octaves: int = 3,
                 frequency: List[int] = 2, persistence: float = 0.5):
    r"""
    Generate a Perlin noise field

    Parameters
    ----------
    shape : array_like
        The shape of the desired image
    frequncy : array_like
        Controls the frequency of the noise, with higher values leading to
        smaller features or more tightly spaced undulations in the brightness.
    porosity : float
        If specified, the returned image will be thresholded to the specified
        porosity.  If not provided, the greyscale noise is returned (default).
    octaves : int
        Controls the texture of the noise, with higher values giving more
        comlex features of larger length scales.
    persistence : float
        Controls how prominent each successive octave is.  Shoul be a number
        less than 1.

    Returns
    -------
    An ND-array of the specified ``shape``.  If ``porosity`` is not given
    then the array contains greyscale values distributed normally about 0.
    Use ``porespy.tools.norm_to_uniform`` to create an well-scale image for
    thresholding.  If ``porosity`` is given then these steps are done
    internally and a boolean image is returned.

    Notes
    -----
    The implementation used here is a bit fussy about the values of
    ``frequency`` and ``octaves``.  (1) the image ``shape`` must an integer
    multiple of ``frequency`` in each direction, and (2) ``frequency`` to the
    power of ``octaves`` must be less than or equal the``shape`` in each
    direction.  Exceptions are thrown if these conditions are not met.

    References
    ----------
    This implementation is taken from Pierre Vigier's
    `Github repo <https://github.com/pvigier/perlin-numpy>`_

    """
    # Parse args
    shape = np.array(shape)
    if shape.size == 1:  # Assume 3D
        shape = np.ones(3, dtype=int)*shape
    res = np.array(frequency)
    if res.size == 1:  # Assume shape as shape
        res = np.ones(shape.size, dtype=int)*res

    # Check inputs for various sins
    if res.size != shape.size:
        raise Exception('shape and res must have same dimensions')
    if np.any(np.mod(shape, res) > 0):
        raise Exception('res must be a multiple of shape along each axis')
    if np.any(shape/res**octaves < 1):
        raise Exception('(res[i])**octaves must be <= shape[i]')
    check = shape/(res**octaves)
    if np.any(check % 1):
        raise Exception("Image size must be factor of res**octaves")

    # Generate noise
    noise = np.zeros(shape)
    frequency = 1
    amplitude = 1
    for _ in tqdm(range(octaves)):
        if noise.ndim == 2:
            noise += amplitude * _perlin_noise_2D(shape, frequency*res)
        elif noise.ndim == 3:
            noise += amplitude * _perlin_noise_3D(shape, frequency*res)
        frequency *= 2
        amplitude *= persistence

    if porosity is not None:
        noise = norm_to_uniform(noise, scale=[0, 1])
        noise = noise > porosity

    return noise