Source code for timagetk.synthetic_data.nuclei_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 timagetk.components.spatial_image import SpatialImage
from timagetk.synthetic_data.util import point_position_optimization


[docs] def nuclei_image_from_point_positions(points, extent=50., voxelsize=(0.5, 0.25, 0.25), nuclei_radius=1.5, nuclei_intensity=10000., point_signals=None, **kwargs): """Create a 3D nuclei image from a dictionary of 3D points. Parameters ---------- points : dict Dictionary with X,Y,Z 3D positions as values extent : float, optional The extent of the output image (in µm) voxelsize : list(float), optional Length-3 list of image Z,Y,X voxel-size (in µm) nuclei_radius : float, optional Radius of the spherical blobs representing nuclei (in µm) nuclei_intensity : float, optional The intensity value of the spherical blobs point_signals : dict, optional Dictionary with [0,1] intensity factors for each point Other Parameters ---------------- dtype : {"uint8", "uint16"} The bit-depth of the intensity image. Returns ------- timagetk.SpatialImage The generated nuclei image """ image_size = [int(extent / v) for v in voxelsize] x, y, z = np.ogrid[0:image_size[2] * voxelsize[2]:voxelsize[2], 0:image_size[1] * voxelsize[1]:voxelsize[1], 0:image_size[0] * voxelsize[0]:voxelsize[0]] points_array = np.array(list(points.values())) cell_distances = np.power(x[np.newaxis] - points_array[:, 0, np.newaxis, np.newaxis, np.newaxis], 2) + \ np.power(y[np.newaxis] - points_array[:, 1, np.newaxis, np.newaxis, np.newaxis], 2) + \ np.power(z[np.newaxis] - points_array[:, 2, np.newaxis, np.newaxis, np.newaxis], 2) density_k = 2. / nuclei_radius density_potential = (1. - np.tanh(density_k * (cell_distances - nuclei_radius))) / 2. density = np.zeros_like(density_potential[0]) for i, p in enumerate(points.keys()): if point_signals is None: density += density_potential[i] else: if p in point_signals: density += point_signals[p] * density_potential[i] img = (nuclei_intensity * density).astype(kwargs.get('dtype', "uint16")) img = np.transpose(img, (2, 1, 0)) from timagetk.io.image import default_image_attributes from timagetk.util import now im_kwargs = default_image_attributes(img, voxelsize=voxelsize) im_kwargs['metadata'] = {'acquisition_date': now()} return SpatialImage(img, **im_kwargs)
[docs] def example_nuclei_image(n_points=100, extent=50., voxelsize=(0.5, 0.25, 0.25), nuclei_radius=1.5, nuclei_intensity=10000., **kwargs): """Generate a synthetic 3D nuclei image. The function creates a 3D image over a cubic volume of a given extent and populates it with randomly scattered nuclei. Nuclei are represented by a spherical blobs of intensity of a same radius. Parameters ---------- n_points : int, optional Number of nuclei in the image. Defaults to ``100``. extent : float, optional The extent of the output image (in µm). Defaults to ``50.``. voxelsize : list(float), optional Length-3 list of image Z,Y,X voxelsize (in µm). Defaults to ``(0.5, 0.25, 0.25)``. nuclei_radius : float, optional Radius of the spherical blobs representing nuclei (in µm). Defaults to ``1.5``. nuclei_intensity : float, optional The intensity value of the spherical blobs. Defaults to ``10000``. Other Parameters ---------------- dtype : {"uint8", "uint16"} The bit-depth of the intensity image. Defaults to ``'uint16'``. Returns ------- timagetk.SpatialImage The generated nuclei image. dict The XYZ-ordered 3D point positions used to generate the nuclei image. Examples -------- >>> import numpy as np >>> import matplotlib.pyplot as plt >>> from timagetk.synthetic_data.nuclei_image import example_nuclei_image >>> from timagetk.visu.mplt import image_plot >>> nuclei_img, points = example_nuclei_image(n_points=10, extent=15., nuclei_radius=1.5, nuclei_intensity=10000) >>> points = np.array(list(points.values())) >>> plt.figure(figsize=(5, 5)) >>> plt.scatter(points[:,0], points[:,1], color='r') # Show X & Y coordinates >>> image_plot(nuclei_img.max(axis=0),plt.gca(),val_range='auto') >>> plt.show() """ image_size = [int(extent / v) for v in voxelsize] center = (np.array(image_size) * np.array(voxelsize) / 2.) points = {} rng = np.random.default_rng() for i in range(n_points): points[i] = center + rng.random(3, dtype=float) point_target_distance = np.power(n_points, 1 / 3.) * nuclei_radius * 1.5 sigma_deformation = nuclei_radius / 5. points = point_position_optimization(points, target_distance=point_target_distance, sigma_deformation=sigma_deformation, force_centering=True, center=center) img = nuclei_image_from_point_positions(points, extent, voxelsize, nuclei_radius, nuclei_intensity, dtype=kwargs.get('dtype', "uint16")) return img, points
[docs] def example_nuclei_signal_images(n_points=100, extent=50., voxelsize=(0.5, 0.25, 0.25), nuclei_radius=1.5, signal_type='random', signal_intensity=10000., **kwargs): """Generate a synthetic 3D nuclei image with a second signal channel. The function creates a 3D image over a cubic volume of a given extent and populates it with randomly scattered nuclei. Nuclei are represented by a spherical blobs of intensity of a same radius. In the second channel, a signal value is associated with each nucleus and multiplied with the intensity of the corresponding spherical blob. The signal distribution can either be random or radially decreasing. Parameters ---------- n_points : int, optional Number of nuclei in the image. Defaults to ``100``. extent : float, optional The extent of the output image (in µm). Defaults to ``50.``. voxelsize : list(float), optional Len-3 list of image Z,Y,X voxelsize (in µm). Defaults to ``(0.5, 0.25, 0.25)``. nuclei_radius : float, optional Radius of the spherical blobs representing nuclei (in µm). Defaults to ``1.5``. signal_type: {'random', 'center'} Whether to use a radially decreasing ('center') or a random signal ('random'). Defaults to ``'random'``. signal_intensity : float, optional The intensity value of the spherical blobs. Defaults to ``10000``. Other Parameters ---------------- dtype : {"uint8", "uint16"} The bit-depth of the intensity image. Defaults to ``'uint16'``. Returns ------- timagetk.SpatialImage The generated nuclei reference image timagetk.SpatialImage The generated signal intensity image dict The random X,Y,Z 3D point positions used to generate the nuclei dict The signal values associated with each nucleus Examples -------- >>> import numpy as np >>> import matplotlib.pyplot as plt >>> from timagetk.synthetic_data.nuclei_image import example_nuclei_signal_images >>> from timagetk.visu.mplt import image_plot >>> nuclei_img, signal_img, points, point_signals = example_nuclei_signal_images(n_points=10, extent=15., nuclei_radius=1.5, signal_intensity=10000) >>> points = np.array(list(points.values())) >>> point_signals = np.array(list(point_signals.values())) >>> fig, axes = plt.subplots(2, 2) >>> fig.set_size_inches(w=4*5., h=5.) >>> axes[0, 0].scatter(points[:,0], points[:,1], color='r') # Show X & Y coordinates >>> axes[0, 1].scatter(points[:,0], points[:,1], c=point_signals, cmap='viridis') # Show X & Y coordinates >>> image_plot(nuclei_img.max(axis=0),axes[1, 0],'gray',val_range='auto') >>> image_plot(signal_img.max(axis=0),axes[1, 1],'gray',val_range='auto') >>> plt.show() """ image_size = [int(extent / v) for v in voxelsize] center = (np.array(image_size) * np.array(voxelsize) / 2.) img, points = example_nuclei_image(n_points, extent, voxelsize, nuclei_radius, signal_intensity, **kwargs) rng = np.random.default_rng() if signal_type == 'random': point_signals = {p: rng.random() for p in points.keys()} elif signal_type == 'center': point_signals = {p: 1. - np.linalg.norm(points[p] - center) / float(extent / 2) for p in points.keys()} else: raise ValueError( f"Unknown `signal_type` value ('{signal_type}'), valid options are: {', '.join(['random', 'center'])}") signal_img = nuclei_image_from_point_positions(points, extent, voxelsize, nuclei_radius, signal_intensity, point_signals, **kwargs) from timagetk.io.image import default_image_attributes from timagetk.util import now im_kwargs = default_image_attributes(img, voxelsize=voxelsize) im_kwargs['metadata'] = {'acquisition_date': now()} sim_kwargs = default_image_attributes(signal_img, voxelsize=voxelsize) sim_kwargs['metadata'] = {'acquisition_date': now()} return SpatialImage(img, **im_kwargs), SpatialImage(signal_img, **sim_kwargs), points, point_signals