Source code for spam.kalisphera.kalisphera

"""
Library of SPAM functions for generating partial volume balls, see Tengattini et al. 2015
Copyright (C) 2020 SPAM Contributors

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

This program 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 GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import numpy

from . import kalispheraToolkit

real_t = '<f8'
# also need to select double or float in kalisphera C call


[docs] def makeSphere(vol, centre, radius): """ This function creates a sphere in a given 3D volume, with analytically-calculated partial-volume effects. Background is assumed to have a greyvalue of zero, and a fully-occupied sphere voxel is considered to have a greyvalue of 1. Greyvalues are added to the volume, so spheres can be added to an existing background. Parameters ---------- vol : 3D numpy array of doubles A 3D image of greylevels (typically zeros) into which sphere(s) should be added centre : 1D or 2D numpy array Either a 3-component vector, or an Nx3 matrix of sphere centres to draw with respect to 0,0,0 in `vol` radius : float or 1D numpy array Raduis(ii) of spheres to draw in `vol` Returns ------- None : function updates vol """ if len(vol.shape) != 3: print("\tkalisphera.makeSphere(), need 3D vol array") return -1 centre = numpy.array(centre, dtype=real_t) # Turn centre into a numpy array in case it is passed as a list-of-lists if len(centre.shape) == 1: centre = numpy.array([centre]) if len(centre.shape) == 2: if type(radius) == float or type(radius) == int: # print("\tkalisphera.makeSphere.run(), Got single radius for multiple spheres... fine") radius = [radius] * centre.shape[0] if len(radius) == centre.shape[0]: for centre, radius in zip(centre, radius): volTemp = numpy.zeros_like(vol, dtype=real_t) # For compatibility with scipy centre of mass # centre+=0.5 # print centre, radius # print vol.sum() kalispheraToolkit.kalisphera(volTemp, numpy.array(centre).astype(real_t), float(radius)) # print vol.sum() vol += volTemp # .copy() return 0 else: print("\tkalisphera.makeSphere(), Got multiple radii, but different number from number of centres") return -1
[docs] def makeBlurryNoisySphere(dims, centre, radius, blur=0, noise=0, flatten=True, background=0.25, foreground=0.75): """ This function creates a sphere or series of spheres in a 3D volume, with analytically-calculated partial-volume effects. This function can flattens overlaps, then adds gaussian blur and then gaussian noise to `makeSphere`. Parameters ---------- dims : 3-component list Dimensions of volume to create centre : 1D or 2D numpy array Either a 3-component vector, or an Nx3 array of sphere centres to draw with respect to 0,0,0 in `vol` radius : float or 1D numpy array Radius(ii) of spheres to draw in `vol` blur : float, optional Standard deviation of the blur kernel (in ~pixels) Default = 0 noise : float, optional Standard devitaion of the noise (in greylevels), noise is on the scale: background=0 and sphere=1 Default = 0 flatten : bool, optional Flatten greyvalues >1 to 1 (caused by overlaps)? Default = True background : float, optional Desired mean greyvalue of the background Default = 0.25 foreground : float, optional Desired mean greyvalue of the background Default = 0.75 Returns ------- vol : the input array Note this is different return behaviour than makeSphere, which doesn't return anything!! """ assert(foreground > background) vol = numpy.zeros(dims, dtype=real_t) makeSphere(vol, centre, radius) if flatten: vol[vol>1]=1 if blur != 0: import scipy.ndimage vol = scipy.ndimage.gaussian_filter(vol, sigma=blur) if noise != 0: vol += numpy.random.normal(size=dims, scale=noise) vol *= float(foreground)-float(background) vol += float(background) return vol