"""
The texture module allows to generate 3D textures for synthetic samples
"""
# Copyright (c) 2020 Idiap Research Institute, http://www.idiap.ch/
# Written by François Marelli <francois.marelli@idiap.ch>
#
# This file is part of CBI Toolbox.
#
# CBI Toolbox is free software: you can redistribute it and/or modify
# it under the terms of the 3-Clause BSD License.
#
# CBI Toolbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# 3-Clause BSD License for more details.
#
# You should have received a copy of the 3-Clause BSD License along
# with CBI Toolbox. If not, see https://opensource.org/licenses/BSD-3-Clause.
#
# SPDX-License-Identifier: BSD-3-Clause
import numpy as np
import noise
from cbi_toolbox.simu import primitives
[docs]def spheres(size, density=1, seed=None):
"""
Generates a texture full of hollow spheres
Parameters
----------
size : int
size of the texture
density : int, optional
spheres density in the texture, by default
seed : int, optional
seed of the rng, default is None
Returns
-------
array [size, size, size]
the texture
"""
dtype = np.float32
n_spheres = int(density * 10000)
max_radius = int(0.1 * size)
min_radius = int(0.02 * size)
max_in_radius = 0.5
min_intens = 0.05
max_intens = 0.2
pad_size = size + 4 * max_radius
volume = np.ones((pad_size, pad_size, pad_size), dtype=dtype)
rng = np.random.default_rng(seed)
for _ in range(n_spheres):
center = (rng.random(3) * (size + 2 * max_radius)
).astype(int) + max_radius
radius = int(rng.uniform(min_radius, max_radius))
in_radius = rng.uniform(0, max_in_radius)
intens = rng.uniform(min_intens, max_intens)
obj = primitives.ball(radius * 2, in_radius=in_radius, dtype=dtype)
volume[center[0] - radius:center[0] + radius, center[1] - radius:center[1] + radius,
center[2] - radius:center[2] + radius] *= (1 - obj * intens)
return 1 - volume[volume.ndim * [slice(2*max_radius, -2*max_radius)]]
[docs]def simplex(size, scale=1, octaves=3, persistence=0.7, lacunarity=3.5, seed=None):
"""
Generates 3D simplex noise
Parameters
----------
size : int
size of the texture
scale : int, optional
scale of the noise, by default 1
octaves : int, optional
number of octaves used, by default 3
persistence : float, optional
relative amplitude of octaves, by default 0.7
lacunarity : float, optional
relative frequency of octaves, by default 3.5
seed : int, optional
seed for the noise, by default None
Returns
-------
array [size, size, size]
the texture
"""
if seed is None:
seed = int(np.random.default_rng().integers(2**10) * scale)
volume = np.empty((size, size, size), dtype=np.float32)
scale /= size
# TODO optimize loops
for x in range(size):
for y in range(size):
for z in range(size):
sample = noise.snoise3(seed + x*scale, seed + y*scale, seed + z*scale,
octaves=octaves, persistence=persistence, lacunarity=lacunarity)
volume[x, y, z] = sample
return volume
if __name__ == '__main__':
import napari
TEST_SIZE = 128
s_spheres = spheres(TEST_SIZE)
s_simplex = simplex(TEST_SIZE)
phantom = primitives.phantom(TEST_SIZE) * (s_simplex * 0.5 + 0.75)
with napari.gui_qt():
viewer = napari.view_image(s_spheres)
viewer.add_image(s_simplex)
viewer.add_image(phantom)