spacr.object_distances

Measure distances within and between segmented objects.

Other spaCR measurement families cover centroid-to-centroid neighbour distances within one object type (over a KD-tree) and the distance from a channel’s intensity centre of mass to the nearest nucleus or pathogen surface. This module adds centre-to-centre, centre-to-surface and surface-to-surface distances between object types, overlap fractions, local-maximum distances, and each object’s radial position relative to its own boundary.

A Euclidean distance transform is computed once for each object-type mask. At every pixel it records the distance to the nearest pixel belonging to that object type, with zero inside an object. Centre-to-surface, surface-to-surface, and local-maximum distances can therefore be obtained by sampling or reducing the precomputed field rather than evaluating every pair of objects. The principal operations are:

centre -> nearest surface      dt_b[centroid_a]
surface -> surface             min(dt_b[a_boundary])
local maximum -> surface       dt_b[peak]

The transform costs O(image pixels) per object type.

Three different quantities are reported as distances between object types:

centre_to_centre between the two centroids. Big for two large

objects that are touching.

centre_to_surface from a’s centroid to the nearest point on ANY b.

Asymmetric: a’s centre to b’s edge is not b’s centre to a’s edge, so both are emitted.

surface_to_surface closest point to closest point. Zero when they

touch; this is the gap between the two objects.

Column names carry no object-type prefix. measure prefixes every measurement family with the object it belongs to, so a column called distance_to_own_boundary here reaches the database as cell_distance_to_own_boundary. A cell_... name here would become cell_cell_....

An object with no partner of the other type gets inf, not NaN; NaN is reserved for “not measured”.

Functions

between_object_types(→ pandas.DataFrame)

Distances from every primary object to every other object type.

intensity_centre_offset([spacing])

How far each channel's intensity centre sits from the geometric one.

interior_distance_transform(mask[, spacing])

Distance from every point inside an object to that object's boundary.

local_maxima(→ numpy.ndarray)

Coordinates of the intensity peaks inside one object.

maxima_distances([spacing])

Where each object's intensity peaks are, and what they are near.

object_distances([spacing])

Every distance this module measures, for one object type.

surface_distance_transform(mask[, spacing])

Distance from every point to the nearest object surface in mask.

Module Contents

spacr.object_distances.between_object_types(masks: Dict[str, numpy.ndarray], *, primary: str, spacing=None) → pandas.DataFrame[source]

Distances from every primary object to every other object type.

Parameters:
  • masks – object type -> label image, all the same shape.

  • primary – the type whose objects are the rows.

  • spacing – voxel size, so the numbers carry physical units.

Returns:

one row per primary object, keyed on label.

For each other object type, the row carries the centre-to-surface, surface-to-surface and nearest centre-to-centre distances (see the module docstring) and the fraction of the object’s pixels that overlap that type. Every row also carries distance_to_own_boundary, relative_radial_position and distance_to_field_edge; a small distance to the field edge indicates an object that may be clipped.

spacr.object_distances.intensity_centre_offset(mask, images, *, primary: str, channels: Sequence[int] = (), spacing=None) → pandas.DataFrame[source]

How far each channel’s intensity centre sits from the geometric one.

Parameters:
  • mask – label image whose instances define rows and geometric centroids.

  • images – aligned intensity field with channels on its final axis, or a single intensity plane.

  • primary – name of the object type represented by mask.

The offset is a single-number measure of polarisation. A uniformly stained object has an offset of about zero; one whose signal is concentrated at one end has a larger offset, which intensity summaries such as the mean do not show.

spacr.object_distances.interior_distance_transform(mask, spacing=None)[source]

Distance from every point inside an object to that object’s boundary.

Parameters:

mask – label or binary image containing the target objects.

The complement of surface_distance_transform(): run on the mask itself, so it is 0 outside and peaks at each object’s deepest point. Read at a centroid it says how far the centre is from its own rim, which is what makes a relative radial position possible.

spacr.object_distances.local_maxima(image, mask, label: int, *, window=None, threshold=None) → numpy.ndarray[source]

Coordinates of the intensity peaks inside one object.

Parameters:
  • image – intensity image aligned with mask.

  • mask – labelled object image that limits the peak search.

  • label – object label whose interior is searched.

  • window – optional tuple of slices (the object’s bounding box, as from scipy.ndimage.find_objects). The search then runs on that window only, which gives the same peaks as the whole image in a fraction of the time; coordinates are still in whole-image indices.

  • threshold – optional lowest intensity a peak must exceed. Pass the whole image’s minimum with window so the window gives the same peaks as the whole image. None uses the searched image’s minimum.

Returns:

an (n, ndim) array, possibly empty.

spacr.object_distances.maxima_distances(masks: Dict[str, numpy.ndarray], images, *, primary: str, channels: Sequence[int] = (), spacing=None) → pandas.DataFrame[source]

Where each object’s intensity peaks are, and what they are near.

Parameters:
  • masks – object-type label images sharing the field geometry.

  • images – the field as (..., channel).

  • primary – object type whose labelled instances define output rows.

  • channels – which channels to find maxima in. Empty means all.

Returns:

one row per primary object, keyed on label.

spacr.object_distances.object_distances(masks: Dict[str, numpy.ndarray], images=None, *, primary: str, channels: Sequence[int] = (), spacing=None, maxima: bool = True) → pandas.DataFrame[source]

Every distance this module measures, for one object type.

The one call the measure pipeline makes. Joined on label so it widens the object’s row like any other measurement family.

Parameters:
  • masks – object type -> label image.

  • images – the field, for the intensity-derived families. None skips them.

  • primary – object type whose instances define the returned rows.

  • maxima – whether to find local maxima. The most expensive part.

spacr.object_distances.surface_distance_transform(mask, spacing=None)[source]

Distance from every point to the nearest object surface in mask.

Parameters:

mask – label or binary image containing the target objects.

The result is zero inside an object. distance_transform_edt measures distance to the nearest zero, so it is run on the inverted mask: the result is 0 on any labelled pixel and grows outward. A lookup at another object’s centroid is therefore the distance to the nearest surface of this type, and two touching objects have a distance of 0.