Source code for timagetk.synthetic_data.labelled_image

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#  Copyright (c) 2022 Univ. Lyon, ENS de Lyon, UCB Lyon 1, CNRS, INRAe, Inria
#  All rights reserved.
#  This file is part of the TimageTK library, and is released under the "GPLv3"
#  license. Please see the LICENSE.md file that should have been included as
#  part of this package.
# ------------------------------------------------------------------------------

import numpy as np
from scipy.cluster.vq import vq

from timagetk.components.labelled_image import LabelledImage
from timagetk.synthetic_data.util import point_position_optimization


[docs] def example_layered_sphere_labelled_image(extent=60., voxelsize=(0.6, 0.6, 0.6), n_points=12, n_layers=1, return_points=False, **kwargs): """Generate a synthetic 3D labelled image representing a spherical tissue. The function creates a 3D labelled image over a cubic volume of a given extent. It consists of successive spherical cell layers of equal height around a central spherical cell. The number of cells in each layer is set so that cells in every layer have similar volumes. Parameters ---------- extent : float, optional The extent of the output image (in µm). Defaults to ``60.``. voxelsize : list(float), optional Length-3 list of image Z,Y,X voxelsize (in µm). Defaults to ``(0.6, 0.6, 0.6)``. n_points : int, optional The number of cells on innermost spherical layer. Defaults to ``12``. n_layers : int, optional The number of layer around the central cell. Defaults to ``1``. return_points : bool, optional Whether to return the points representing the cell centers. Defaults to ``False``. Returns ------- timagetk.LabelledImage The generated labelled cell image dict, optional The 3D X,Y,Z point positions used to generate the cells Examples -------- >>> from timagetk.synthetic_data.labelled_image import example_layered_sphere_labelled_image >>> seg_img = example_layered_sphere_labelled_image() >>> print(seg_img) LabelledImage object with following metadata: - shape: (100, 100, 100) - ndim: 3 - dtype: uint16 - axes_order: ZYX - voxelsize: [0.6, 0.6, 0.6] - unit: 1e-06 - origin: [0, 0, 0] - extent: [59.4, 59.4, 59.4] - acquisition_date: None - not_a_label: 0 >>> from timagetk.visu.stack import orthogonal_view >>> v = orthogonal_view(seg_img, cmap='glasbey', val_range='auto') """ rng = np.random.default_rng(2021) size = np.round(extent / np.array(voxelsize)).astype(int) center = np.array([extent, extent, extent], float) / 2. coords = np.transpose(np.mgrid[0:size[0], 0:size[1], 0:size[2]], (1, 2, 3, 0)).reshape((np.prod(size), 3)).astype(int) coords_points = np.array(coords, float) * np.array(voxelsize) coords_distances = np.linalg.norm(coords_points - center, axis=1) points = {2: center} layer_img = {} for layer in range(n_layers): layer_n_points = n_points * np.power(layer + 1, 2) radius = (layer + 1) * extent / float(2 * n_layers + 1) layer_points = {} max_point_id = np.max(list(points.keys())) for p in range(layer_n_points): theta = rng.random() * 2. * np.pi phi = rng.random() * np.pi - np.pi / 2. sphere_point = np.array([np.cos(theta) * np.cos(phi), np.sin(theta) * np.cos(phi), np.sin(phi)]) layer_points[max_point_id + 1 + p] = center + radius * sphere_point point_target_area = 4. * np.pi * np.power(radius, 2.) / float(layer_n_points) point_target_distance = np.power(point_target_area / np.pi, 0.5) sigma_deformation = (extent / 100.) * (20. / layer_n_points) omega_attraction = 0.1 * extent / 100. omega_repulsion = 100.0 * np.power(extent / 100., 2) layer_points = point_position_optimization(layer_points, omega_attraction=omega_attraction, omega_repulsion=omega_repulsion, target_distance=point_target_distance, sigma_deformation=sigma_deformation, constraint_radius=True, center=center, radius=radius) for p in layer_points.keys(): points[p] = layer_points[p] layer_points_labels = np.array(list(layer_points.keys())) layer_points_array = np.array(list(layer_points.values())) labels = layer_points_labels[vq(coords_points, layer_points_array)[0]] layer_img[layer + 1] = np.ones(size, np.uint16) layer_img[layer + 1][tuple(np.transpose(coords))] = labels img = np.ones(size, np.uint16) for layer in range(n_layers): layer_coords = coords[(coords_distances > (2 * layer + 1) * extent / float(4 * (n_layers + 1))) & ( coords_distances <= (2 * layer + 3) * extent / float(4 * (n_layers + 1)))] img[tuple(np.transpose(layer_coords))] = layer_img[layer + 1][tuple(np.transpose(layer_coords))] center_coords = coords[coords_distances <= extent / float(4 * (n_layers + 1))] img[tuple(np.transpose(center_coords))] = 2 ext_coords = coords[coords_distances > (n_layers + 1) * extent / float(2 * (n_layers + 2))] img[tuple(np.transpose(ext_coords))] = 1 from timagetk.io.image import default_image_attributes from timagetk.util import now img_kwargs = default_image_attributes(img, voxelsize=voxelsize) img_kwargs["acquisition_date"] = now() img = LabelledImage(img, not_a_label=0, **img_kwargs) for p in points.keys(): # go from ZYX image convention to XYZ coordinates points[p] = points[p][[2, 1, 0]] _return = (img,) if return_points: _return += (points,) if len(_return) == 1: return _return[0] return _return