pyssam package

Submodules

pyssam.datasets module

Some basic datasets for unit-testing and training examples

class pyssam.datasets.Torus(inner_radius_mean=1, outer_radius_mean=2, inner_radius_std=0.3, outer_radius_std=0.15)[source]

Bases: object

make_dataset(n_samples)[source]
class pyssam.datasets.Tree(length: list = [3.8, 4.2], length_ratio: list = [0.2, 0.8], angle: list = [5, 60], num_extra_ends: int = 0)[source]

Bases: object

Create tree object based on a set of pre-defined parameters.

Parameters:
  • length (list) – Minimum and maximum values for tree first branch segment

  • length_ratio (list) – Minimum and maximum values to sample for length ratio between parent and child branches

  • angle (list) – Minimum and maximum values to sample for angle between child branch and parent branch vectors

  • num_extra_ends (int) – Number of additional bifurcation levels to generate

Examples

>>> import pyssam
>>> tree_class = pyssam.datasets.Tree()
>>> print(tree_class.make_tree_landmarks().shape)
(8, 3)
>>> tree_class = Tree(num_extra_ends=2)
>>> print(tree_class.make_tree_landmarks().shape)
(32, 3)
graph_to_coords(graph: DiGraph) array[source]

Convert “position” key from all nodes in graph to a numpy array of coordinates.

Parameters:

graph (nx.DiGraph) – Graph with “position” entry in nodal attributes

make_tree() DiGraph[source]

Make a tree structure based on a baseline graph by randomly creating nodal coordinates (also determined by angle, length and length_ratio)

Returns:

graph – Randomly created graph that can be used with shape model

Return type:

nx.DiGraph

make_tree_landmarks() array[source]

Make tree landmarks based on a baseline graph by randomly creating nodal coordinates.

Returns:

landmarks – Landmarks for nodal coordinates on randomly created graph that can be used with shape model

Return type:

array_like

pyssam.statistical_model_base module

class pyssam.statistical_model_base.StatisticalModelBase[source]

Bases: ABC

Abstract base class for statistical model.

compute_dataset_mean(dataset_columnvector) array[source]

Average over all samples to produce a column-vector of the mean shape, appearance, or other quantity included in model.

Returns:

mean_columnvector

Return type:

array_like

create_pca_model(dataset: ndarray, desired_variance: float = 0.9) None[source]

Perform principal component analysis to create statistical model and extract modelling quantites from the PCA class.

Parameters:
  • dataset (array_like) – 2D array of data to model, where each row on the first axis is one sample and each column on the second axis is e.g. shape or appearance for a landmark

  • desired_variance (float) – Fraction of total variance to be described by the reduced-dimension model

Return type:

None

Raises:
  • Warning – If mean of each sample in dataset not equal to 0

  • Warning – If standard deviation of each sample in dataset not equal to 1

do_pca(dataset: ndarray, desired_variance: float = 0.9) Tuple[Any, int][source]

Fit principal component analysis to given dataset.

Parameters:
  • dataset (array_like) – 2D array of data to model, where each row on the first axis is one sample and each column on the second axis is e.g. shape or appearance for a landmark

  • desired_variance (float) – Fraction of total variance to be described by the reduced-dimension model

Returns:

  • pca (sklearn.decomposition._pca.PCA) – Object containing fitted PCA information e.g. components, explained variance

  • required_mode_number (int) – Number of principal components needed to produce desired_variance

Raises:
  • Warning – If mean of each sample in dataset not equal to 0

  • Warning – If standard deviation of each sample in dataset not equal to 1

fit_model_parameters(input_sample, num_modes: int = 1000000) array[source]

See docs in static function pyssam.fit_model_parameters

landmark_data_to_column(landmark_array)[source]

Reduce an containing spatial information on landmarks in cartesian coordinates to essentially a set of stacked column-vectors. Remove any array dimensions with only one size e.g. (1, 1000, 3) -> (3000,)

Parameters:

landmark_array (array_like) – Landmarks spatial coordinates with 2 or 3 dimensions. The final dimension should size of e.g. 3 for coordinates in 3D space.

Returns:

reduced_array – Landmarks where the N-dimensional array is collapsed to N-1 dimensions.

Return type:

array_like

Examples

>>> import numpy as np
>>> import pyssam
>>> landmarks_in = np.random.uniform(0, 100, size=(5, 100, 3))
>>> ssm = pyssam.SSM(landmarks_in)
>>> print(ssm.landmark_data_to_column(landmarks_in).shape)
(5, 300)
static load_model(filename)[source]
morph_model(model_parameters: array, num_modes: int = 1000000) array[source]

See docs in static function pyssam.morph_model

property num_landmarks

Property for number of landmarks in a shape model entry.

Should set by default in model class, e.g. in pyssam.SSM.

save_model(filename, num_modes=10000000)[source]
scale_dataset(dataset)[source]

Take 2D or 3D array representing landmarks for multiple samples in a population, and scale to have zero mean and unit std dev.

Parameters:

dataset (array_like) – Landmarks for multiple samples in a population, with 2 or 3 dimensions

Returns:

scaled_dataset – Landmarks for multiple samples, each centered on mean = 0 and std dev = 1

Return type:

array_like

Raises:

AssertionError – If number of dimensions on input data are not equal to 2 or 3

Examples

>>> import numpy as np
>>> import pyssam
>>> landmarks_in = np.random.uniform(0, 100, size=(5, 100, 3))
>>> ssm = pyssam.SSM(landmarks_in)
>>> scaled_landmarks = ssm.scale_dataset(landmarks_in)
>>> print(abs(round(scaled_landmarks.mean(), 5)), round(scaled_landmarks.std(), 5))
0.0 1.0
pyssam.statistical_model_base.fit_model_parameters(input_sample, pca_model_components: ndarray, pca_model_std: array, mean_dataset_columnvector: ndarray, num_modes: int = 1000000) array[source]

Find the model parameters which best match the given input_sample with the trained pca model. Assumes that the shape can be described by input_sample pprox dataset_mean + model_modes cdot model_std.

Parameters:
  • input_sample (array_like) – Column-vector representing landmark information (e.g. shape, appearance)

  • pca_model_components (array_like) – eigenvectors of covariance matrix, obtain by PCA.

  • pca_model_std (array_like) – eigenvalues of covariance matrix, obtain by PCA.

  • mean_dataset_columnvector (array_like) – Array of dataset mean

  • num_modes (int) – Number of principal components (or `modes’) to include in model to morph. By default this is set to a high number to set all modes as included.

Returns:

model_parameters – model parameters used to perturb each principal component by some amount 1D array, where values should all be within +/- 3.

Return type:

array_like

pyssam.statistical_model_base.morph_model(mean_dataset_columnvector: array, pca_model_components: ndarray, model_parameters: array, pca_model_std: array, num_modes: int = 1000000) array[source]

Morph the mean dataset based on the PCA weights and variances, with some user-defined model parameters to create a new sample.

Parameters:
  • mean_dataset_columnvector (array_like) – mean shape of the training data in a 1D array.

  • pca_model_components (array_like) – eigenvectors of covariance matrix, obtain by PCA.

  • model_parameters (array_like) – model parameters used to perturb each principal component by some amount 1D array, where values should all be within +/- 3.

  • num_modes (int) – Number of principal components (or `modes’) to include in model to morph. By default this is set to a high number to set all modes as included.

Returns:

morphed_output – A 1D array which has been perturbed from the mean shape based on the pca_model and model_parameters.

Return type:

array_like

Raises:
  • Warning – If model parameters are outwith +/- 3

  • AssertionError – If number of dimension in pca_model_components not equal to 2

pyssam.ssm module

Create statistical shape model (SSM) for a set of shapes.

class pyssam.ssm.SSM(landmarks: ndarray)[source]

Bases: StatisticalModelBase

Create statistical shape model for a set of shapes.

Parameters:

landmarks (array_like) – Coordinates for landmarks in dataset, with 3 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample. Third dimension has size equal to the number of spatial dimensions occupied by the shapes (e.g. 3D or 2D).

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_landmarks = 10
>>> landmarks = np.random.normal(size=(num_samples, num_landmarks, 3))
>>> ssm = pyssam.SSM(landmarks)
>>> print(ssm.landmarks_columns_scale.shape)
(5, 30)
>>> print(ssm.compute_dataset_mean().shape)
(30,)

pyssam.sam module

Create statistical appearance model (SAM) for a set of samples.

class pyssam.sam.SAM(appearance: ndarray)[source]

Bases: StatisticalModelBase

Create statistical appearance model for a set of samples.

Parameters:

appearance (array_like) – Appearances for landmarks in dataset, with 2 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample.

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_landmarks = 10
>>> appearances = np.random.normal(size=(num_samples, num_landmarks))
>>> sam = pyssam.SAM(appearances)
>>> print(sam.appearance_scale.shape)
(5, 10, 1)
>>> print(sam.compute_dataset_mean().shape)
(10,)

pyssam.ssam module

Create statistical shape and appearance model (SSAM) for a set of samples.

class pyssam.ssam.SSAM(landmarks: ndarray, appearance: ndarray)[source]

Bases: StatisticalModelBase

Create statistical shape and appearance model for a set of samples.

Parameters:
  • landmarks (array_like) – Coordinates for landmarks in dataset, with 3 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample. Third dimension has size equal to the number of spatial dimensions occupied by the shapes (e.g. 3D or 2D).

  • appearance (array_like) – Appearances for landmarks in dataset, with 2 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample.

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_landmarks = 10
>>> landmarks = np.random.normal(size=(num_samples, num_landmarks, 3))
>>> appearances = np.random.normal(size=(num_samples, num_landmarks))
>>> ssam = pyssam.SSAM(landmarks, appearances)
>>> print(ssam.shape_appearance_columns.shape)
(5, 40)
>>> print(ssam.compute_dataset_mean().shape)
(40,)

pyssam.utils module

Utilities to aid modelling classes.

class pyssam.utils.AppearanceFromXray(imgs_all: ndarray, img_origin: ndarray, img_spacing: ndarray)[source]

Bases: object

Extract appearance information from X-ray.

Parameters:
  • imgs_all (array_like) – 3D array for all images in dataset, where the first dimension is the number of samples. Second and third dimensions are the image pixels.

  • img_origin (array_like) – 2D array for spatial coordinates of origins for all images in dataset. The first dimension is the number of samples. If one image is used, only x and y are needed to expected size is 2.

  • img_spacing (array_like) – 2D array for pixel spacing of all images in dataset. The first dimension is the number of samples. If one image is used, only x and y are needed to expected size is 2.

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_pixels = 250
>>> image_all = np.random.rand(num_samples, num_pixels, num_pixels)
>>> origin_all = np.zeros((num_samples, 2))
>>> spacing_all = np.ones((num_samples, 2))
>>> appearance_helper = pyssam.utils.AppearanceFromXray(image_all, origin_all, spacing_all)
using 2D coordinates for X-ray
>>> print(appearance_helper.pixel_coordinates.shape)
(5, 250, 2)
>>> appearance_helper = pyssam.utils.AppearanceFromXray(np.random.rand(250,250), np.zeros(3), np.ones(3))
using 3D coordinates for XR
>>> print(appearance_helper.pixel_coordinates.shape)
(1, 250, 3)
all_landmark_density(landmarks: ndarray) ndarray[source]

Returns density of all landmarks in a dataset based on comparing landmark coordinates to spatial coordinates of pixels in X-rays.

Parameters:
  • landmarks (array_like) – Landmark coordinates used to find appearance. Array has 3 dimensions with shape (num_samples, num_landmarks, 2)

  • img (array_like) – Array of grey-values from X-rays, with 3 dimensions and shape is (num_samples, num_x_pixels, num_y_pixels). Images should be square (meaning same number of pixels in x and y axes).

  • pixel_coordinates (array_like) – Spatial coordinates corresponding to each voxel, with shape with shape (num_samples, num_x_pixels, 2)

Returns:

density – Normalised grey-value for each landmark location, with shape (num_samples, num_landmarks).

Return type:

array_like

compute_landmark_density(landmarks: ndarray, img: ndarray, pixel_coordinates: ndarray) ndarray[source]

Find the gray value at each landmark based on nearest neighbor interpolation to pixel coordinates on image. The grayvalues are all normalised to zero mean and unit variance.

Parameters:
  • landmarks (array_like) – Array of all landmarks for one sample. Expected shape is 2D, where first dimension has size equal to number of landmarks and second dimension has size of two.

  • img (array_like) – Image to extract appearance from. Expected 2D array with equal size in first and second dimensions to represent pixels.

  • pixel_coordinates – Array with spatial locations of each pixel. Note that pixel_coordinates axis=1 value assumes a square figure (same number of x and y pixels)

Returns:

landmark_grayvalue – 1D array of grey value for each landmark.

Return type:

array_like

Raises:

AssertionError – If shape of input arguments do not agree.

radiograph_to_realworld_coordinates(img: ndarray, origin: ndarray, spacing: ndarray) ndarray[source]

Get 2D or 3D set of coordinates (xy or xyz) for image pixels.

Parameters:
  • imgs (array_like) – 3D array for all images in dataset, where the first dimension is the number of samples. Second and third dimensions are the image pixels.

  • origin (array_like) – 2D array for spatial coordinates of origins for all images in dataset. The first dimension is the number of samples. Second dimension is the number of spatial dimensions If one image is used, only x and y are needed to expected size is 2.

  • spacing (array_like) – 2D array for pixel spacing of all images in dataset. The first dimension is the number of samples. Second dimension is the number of spatial dimensions If one image is used, only x and y are needed to expected size is 2.

Returns:

pixel_coordinates – Array with spatial locations of each pixel.

Return type:

array_like

Raises:
  • AssertionError – If final dimension of spacing has shape not equal to 2 or 3.

  • AssertionError – If size of final two dimensions of img not equal to each other (square image)

radiograph_to_realworld_coordinates_2D(img: ndarray, origin: ndarray, spacing: ndarray) ndarray[source]
radiograph_to_realworld_coordinates_3D(img: ndarray, origin: ndarray, spacing: ndarray) ndarray[source]
pyssam.utils.euclidean_distance(x, y) ndarray[source]

Finds the euclidean distance between two arrays x, y.

Parameters:
  • x (array_like) – Coordinates as 1D or 2D array

  • y (array_like) – Coordinates as 1D or 2D array

pyssam.utils.loadXR(file) ndarray[source]

Take input X-ray as png (or similar) and convert to grayscale np array with range 0 to 1.

Parameters:

file (str) – Image file name of X-ray.

Returns:

grayscale_image – Pixel values as grayscale with range [0:1].

Return type:

array_like

pyssam.morph_mesh module

Create a surface mesh by morphing a template mesh and landmarks to a new set of landmarks. This is done using a radial basis function with a gaussian kernel. Source: Grassi et al. (2011) Medical Engineering & Physics.

class pyssam.morph_mesh.MorphTemplateMesh(landmark_target, landmark_template, mesh_template, kernel_width=0.3, smooth=False)[source]

Bases: object

Create a mesh for a new set of landmarks based on a pre-existing ‘template’ mesh, for which we already have a set of landmarks. This is done using a radial basis function with a gaussian kernel. Source: Grassi et al. (2011) Medical Engineering & Physics.

Note that this requires the meshes are already aligned. In rare cases, the error may be high. In this case, I would suggest trying a template that is closer to the target if available.

Examples

>>> import pyssam
>>> torus = pyssam.datasets.Torus()
>>> torus_mesh_list = torus.make_dataset(2)
>>> landmark_coordinates = [sample_i.points[::10] for sample_i in torus_mesh_list]
>>> mesh_target_actual = torus_mesh_list[-1]
>>> mesh_target_computed = pyssam.morph_mesh.MorphTemplateMesh(
        landmark_target=landmark_coordinates[-1],
        landmark_template=landmark_coordinates[0],
        mesh_template=torus_mesh_list[0]
    ).mesh_target
>>> volume_error = 100.0 * abs(mesh_target_computed.volume() - mesh_target_actual.volume()) / mesh_target_actual.volume()
>>> print("volume error below 5%?", volume_error < 5.0)
True
clean_new_mesh(mesh_target)[source]

Use trimesh functionality to check mesh is watertight and do some cleaning operations and smoothing if desired.

Parameters:

mesh_target (vedo.Mesh) – vedo object containing coordinates and face connectivity for new surface mesh

Returns:

mesh_target – vedo object containing coordinates and face connectivity for new surface mesh

Return type:

vedo.Mesh

create_new_mesh(coords)[source]

Create a mesh from a set of coordinates, and faces of the template mesh.

Parameters:

coords (array_like) – A set of coordinates corresponding to vertices on a new mesh. Ordering must be consistent with self.mesh_template.points

Returns:

mesh – vedo object containing coordinates and face connectivity for new surface mesh

Return type:

vedo.Mesh

do_mesh_morphing()[source]

Compute coordinates of vertices on new mesh (corresponding to landmark_target). The new coordinates are then used to create a new mesh, where face connectivity is the same as the template mesh. The new mesh is checked for watertightness, and some cleanup is done.

gaussian_kernel(landmark_template, template_coords_i)[source]

Function to find distance between a coordinate and all surrounding landmarks. We use a Gaussian kernel to smooth how the surrounding landmarks act on the point.

Parameters:
  • landmark_template (array_like) – Landmarks of the template shape (which we already have a mesh for), shape (N,3).

  • template_coords_i (array_like) – coordinates on the template surface mesh, shape (3).

Returns:

distances – Scalar value of distances between all landmarks and the template mesh coordinate.

Return type:

array_like

get_weights(landmark_target, landmark_template, template_coords_i, kernel_function)[source]

Find weight coefficients that control how the template mesh is morphed to the new geometry, based on the distance between the ‘template’ and ‘target’ landmarks (which are in correspondence, so the ordering is consistent).

For more information, see equations (1) and (2) in Grassi et al. (2011) (Medical Engineering & Physics).

Parameters:
  • landmark_target (array_like) – Landmarks of the new shape which we want to morph the mesh to, shape (N,3).

  • landmark_template (array_like) – Landmarks of the template shape (which we already have a mesh for), shape (N,3).

  • template_coords_i (array_like) – coordinates on the template surface mesh.

Returns:

weights – Weights are coefficients that control how strongly the kernel effects each point.

Return type:

array_like

scale_and_align_coordinates(landmark_target, landmark_template, coords_template)[source]

Scale the template landmarks and mesh coordinates to the same size as the target landmarks.

Parameters:
  • landmark_target (array_like) – Landmarks of the new shape which we want to morph the mesh to, shape (N,3).

  • landmark_template (array_like) – Landmarks of the template shape (which we already have a mesh for), shape (N,3).

  • template_coords_i (array_like) – coordinates on the template surface mesh.

Returns:

  • landmark_target (array_like) – Landmarks of the new shape which we want to morph the mesh to, scaled to 1 std-dev

  • landmark_template (array_like) – Landmarks of the template shape, scaled to same scale as target landmarks.

  • template_coords_i (array_like) – coordinates on the template surface mesh, scaled to same scale as target landmarks.

Module contents

class pyssam.SAM(appearance: ndarray)[source]

Bases: StatisticalModelBase

Create statistical appearance model for a set of samples.

Parameters:

appearance (array_like) – Appearances for landmarks in dataset, with 2 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample.

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_landmarks = 10
>>> appearances = np.random.normal(size=(num_samples, num_landmarks))
>>> sam = pyssam.SAM(appearances)
>>> print(sam.appearance_scale.shape)
(5, 10, 1)
>>> print(sam.compute_dataset_mean().shape)
(10,)
class pyssam.SSAM(landmarks: ndarray, appearance: ndarray)[source]

Bases: StatisticalModelBase

Create statistical shape and appearance model for a set of samples.

Parameters:
  • landmarks (array_like) – Coordinates for landmarks in dataset, with 3 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample. Third dimension has size equal to the number of spatial dimensions occupied by the shapes (e.g. 3D or 2D).

  • appearance (array_like) – Appearances for landmarks in dataset, with 2 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample.

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_landmarks = 10
>>> landmarks = np.random.normal(size=(num_samples, num_landmarks, 3))
>>> appearances = np.random.normal(size=(num_samples, num_landmarks))
>>> ssam = pyssam.SSAM(landmarks, appearances)
>>> print(ssam.shape_appearance_columns.shape)
(5, 40)
>>> print(ssam.compute_dataset_mean().shape)
(40,)
class pyssam.SSM(landmarks: ndarray)[source]

Bases: StatisticalModelBase

Create statistical shape model for a set of shapes.

Parameters:

landmarks (array_like) – Coordinates for landmarks in dataset, with 3 dimensions. First dimension has size equal to the number of samples. Second dimension has size equal to the number of landmarks per sample. Third dimension has size equal to the number of spatial dimensions occupied by the shapes (e.g. 3D or 2D).

Examples

>>> import numpy as np
>>> import pyssam
>>> num_samples = 5
>>> num_landmarks = 10
>>> landmarks = np.random.normal(size=(num_samples, num_landmarks, 3))
>>> ssm = pyssam.SSM(landmarks)
>>> print(ssm.landmarks_columns_scale.shape)
(5, 30)
>>> print(ssm.compute_dataset_mean().shape)
(30,)