acia.base#

All basic functionality for acia

acia.base.unpack(data, function)[source]#
class acia.base.Instance[source]#

Bases: object

Cell instance based on an image mask and a label

__init__(mask, frame, label, id=None, score=None, bbox=None)[source]#

Create an object instance

Parameters:
  • mask (np.ndarray) – mask of the object where the object pixels are marked with [label] value

  • frame (int) – frame in the time-lapse

  • label (int) – label of the object (as marked in the mask)

  • id (_type_, optional) – Unique identifier for the object. Defaults to None.

  • score (float, optional) – E.g. confidence of the detection method. Defaults to None.

  • bbox (tuple[slice, slice], optional) – this label’s (rows, cols) bounding box within mask, as returned by scipy.ndimage.find_objects. Every derived geometry is computed inside it, so supplying it saves locating the label – the only step that still has to look at the whole frame. One find_objects call yields the boxes for a whole frame at once (see overlay_from_masks()). Derived lazily when omitted.

property mask: ndarray#
property label#
property binary_mask#

Full-frame boolean mask of this instance.

Kept frame-sized because callers overlay it on the image (see toMask() and the fluorescence extractor). Shape-derived properties use _cropped_mask instead.

property center#
property area: float#

Compute the area inside the contour

Returns:

[float] – area

toMask(height, width)[source]#

Render contour mask onto new image

height: height of the image width: width of the image

property polygon: Polygon | MultiPolygon | None#

Outline of this instance, traced from its mask.

Traced inside the label’s bounding box and then shifted back into frame coordinates. Polygonising the full frame instead – which is what this did – costs O(frame) per cell, so the same cell got ~4x more expensive each time the image dimensions doubled.

property is_fragmented: bool#

Whether this instance’s mask has more than one connected component.

Such a mask has no single outline, so coordinates (and draw()) can only represent its largest part – see largest_polygon(). Lets a caller that is about to persist or render many instances report how many are affected instead of losing the smaller parts silently.

property coordinates: ndarray#

Extract contour coordinates

A mask with disconnected components has no single outline; its largest part is used (see largest_polygon()), matching what draw() renders. is_fragmented reports when that applies.

Raises:

ValueError – if the polygon is not valid or None

Returns:

np.ndarray – Nx2 contour coordinates of the polygon

draw(image, draw=None, outlineColor=(255, 255, 0), fillColor=None)[source]#

Draws instance onto an image

Parameters:
  • image (np.array | PIL.Image) – the image to draw onto

  • draw (PIL.ImageDraw, optional) – Drawing Tool. Defaults to None.

  • outlineColor (tuple, optional) – Color of the Instance contour. None means no contour is drawn. Defaults to (255, 255, 0).

  • fillColor (tuple, optional) – Color of the contour fill. Defaults to None (no filling).

Returns:

np.array | PIL.Image – The image containing the drawn contour.

class acia.base.Contour[source]#

Bases: object

Class for object contour detection (e.g. Cell object)

__init__(coordinates, score, frame, id, label=None)[source]#

Create Contour

Parameters:
  • coordinates (np.ndarray) – coordinates in (x,y) list

  • score (float) – segmentation score

  • frame (int) – frame index

  • id (any) – unique id

  • label – class-defining label of the contour

property coordinates: ndarray#

The contour outline as an (N, 2) array of (x, y) points.

Note that mutating the returned array in place (cont.coordinates[0] = ...) does not invalidate the cached polygon; assign to the attribute instead, as scale() does.

toMask(height, width)[source]#

Render contour mask onto new image

height: height of the image width: width of the image

draw(image, draw=None, outlineColor=(255, 255, 0), fillColor=None)[source]#
scale(scale)[source]#

Apply scale factor to contour coordinates

Parameters:

scale (float) – the multplication factor

property center#
property area: float#

Compute the area inside the contour

Returns:

[float] – area

property polygon: Polygon#

Shapely outline built from coordinates (cached).

Cached because a single extraction run reads it several times per contour – once per geometry property, plus once per filter – and rebuilding the polygon each time was a measurable share of that.

class acia.base.Overlay[source]#

Bases: object

Overlay contains Contours at different frames and provides functionalities iterate and modify them

__init__(contours, frames=None, timepoints=None, frame_interval=None)[source]#
Parameters:

contours (Sequence[Contour | Instance])

add_contour(contour)[source]#
Parameters:

contour (Contour | Instance)

add_contours(contours)[source]#
Parameters:

contours (Sequence[Contour | Instance])

numFrames()[source]#
frames()[source]#
property timepoints#

Per-frame pint Quantity of timepoints, or None if uncalibrated.

property timestamps#

Pint Quantity of per-contour timestamps (in contours order).

with_timepoints(timepoints)[source]#

Attach explicit per-frame timepoints (pint) and stamp each detection.

Return type:

Overlay

with_frame_interval(interval)[source]#

Attach a scalar frame interval (pint) and stamp each detection.

Return type:

Overlay

scale(scale)[source]#

Scale the contour with the specified scale factor

Applies the scale factor to all coordinates individually

Parameters:

scale (float) – [description]

croppedContours(cropping_parameters)[source]#
Parameters:

cropping_parameters (tuple[slice, slice])

time_iterator(start_frame=None, end_frame=None, frame_range=None)[source]#
Return type:

Iterable[Overlay]

timeIterator(startFrame=None, endFrame=None, frame_range=None)[source]#

Creates an iterator that returns an Overlay for every frame between starFrame and endFrame

startFrame: first frame number endFrame: last frame number

Return type:

Iterable[Overlay]

toMasks(height, width, binary_mask=True)[source]#

Turn the individual overlays into masks. For every time point we create a mask of all contours.

returns: List of masks (np.ndarray[bool])

height: height of the image width: width of the image

Return type:

list[ndarray]

draw(image, outlineColor=None, fillColor=None)[source]#

Draw an overly onto an image frame. Hint: overlay should only contain contours for a single frame

Parameters:
  • image (np.ndarray | Image) – Image to draw onto

  • outlineColor (str | Callable[[Contour], tuple[int]], optional) – Color of the object outlines. If this is a function, the function computes the color for every contour/instance individually. Defaults to None (no contour is drawn).

  • fillColor (str | Callable[[Contour], tuple[int]], optional) – Fill color of the object. If this is a function, the function computes the color for every contour/instance individually. Defaults to None (no fill). Defaults to None.

Returns:

np.ndarray | Image – the updated image object

Return type:

ndarray | Image

class acia.base.BaseImage[source]#

Bases: object

Base class for an image from an image source

property raw#
property num_channels#
get_channel(channel)[source]#
Parameters:

channel (int)

class acia.base.ArrayImage[source]#

Bases: BaseImage

A BaseImage backed directly by a numpy array (e.g. a cropped frame).

__init__(content, frame=None)[source]#
Parameters:
property raw#
property num_channels#
get_channel(channel)[source]#
Parameters:

channel (int)

class acia.base.Processor[source]#

Bases: object

Base class for a processor

class acia.base.ImageSequenceSource[source]#

Bases: Iterable[BaseImage], Sized

Base class for an image sequence source (e.g. Tiff, OMERO, png, …).

Supports numpy-style indexing over the (T, H, W, C) axes:

  • src[5] -> the frame at index 5 (a BaseImage)

  • src[::2] -> a view sequence of every second frame

  • src[3:23, 10:90, 10:90, 0] -> a cropped, single-channel subsequence

property num_channels: int#
property size_t: int#
property size_h: int#
property size_w: int#
property size_c: int#
get_frame(frame)[source]#
Parameters:

frame (int)

Return type:

BaseImage

property timepoints#

Per-frame pint Quantity of timepoints, or None if uncalibrated.

property pixel_size#

Pint length per pixel (scalar or [y, x]), or None.

with_frame_interval(interval)[source]#

Tag this source with a scalar frame interval (pint); returns self.

with_timepoints(timepoints)[source]#

Tag this source with explicit per-frame timepoints (pint); returns self.

with_pixel_size(pixel_size)[source]#

Tag this source with a pixel size (pint length per pixel); returns self.

to_channel(c)[source]#

Return a lazy single-channel view of this source.

Parameters:

c (int) – the channel index to select.

Returns:

ImageSequenceSource – a view of this source with only channel c (equivalent to self[..., c]).

Return type:

ImageSequenceSource

crop_rotated(spec)[source]#

Return a lazy rotated-rectangle crop view of this source.

The crop is defined by a RotatedCropSpec (center, size, angle). Each frame is warped on demand so the resulting source stays lazy and the parent’s calibration (pixel_size/timepoints) is preserved.

Parameters:

spec (RotatedCropSpec) – The rotated-rectangle crop specification.

Returns:

RotatedCropSequenceSource – A lazy straightened crop of this source.

Return type:

RotatedCropSequenceSource

register(transforms, *, on_missing='warn')[source]#

Return a lazy drift-corrected view of this source.

Each frame is corrected on demand via acia.registration.apply_correction() using the transform stored for that frame index.

Parameters:
Returns:

RegisteredSequenceSource – A lazy corrected view of this source.

Return type:

RegisteredSequenceSource

to_rgb(*, channel=0, colors=None)[source]#

Return a lazy (H, W, 3) uint8 RGB view of this source.

With colors=None (the default), renders channel in grayscale: that channel’s plane is normalized to uint8 via acia.notebook.normalize_to_uint8(), then triplicated across the color axis. With colors, renders a per-channel color composite: each channel present in colors is normalized independently, scaled by its assigned color, and additively blended (clipped to [0, 255]); channels not present in colors are not rendered.

Parameters:
  • channel (int) – Channel index to render in grayscale mode. Ignored when colors is given. Defaults to 0.

  • colors (dict[int, str] | None) – Optional mapping of channel index -> color, where each color is a hex string (e.g. "#00FF00") or a name from acia.colors.CHANNEL_COLORS (case-insensitive). See acia.colors.resolve_channel_color(). Defaults to None (grayscale mode).

Returns:

RGBSequenceSource – A lazy view of this source whose get_frame(t) yields (H, W, 3) uint8 frames. No frame is read or converted until it is accessed.

Raises:

ValueError – if any color in colors is not a known channel name and not a color matplotlib.colors.to_rgb() can parse.

Return type:

RGBSequenceSource

materialize()[source]#

Eagerly freeze this (possibly lazy) source into an in-memory source.

Stacks every frame into a single (T, H, W, C) array, normalizing grayscale (H, W) frames to (H, W, 1), and returns a THWCSequenceSource carrying the same pixel_size/timepoints. This trades RAM for repeated warp/IO CPU and lets a large parent be released once a small ROI has been extracted.

Frames are copied into a pre-allocated output array one at a time instead of being collected in a list first: a frame’s raw is often only a view into a much larger parent buffer (a slice of a stack, a channel selection, a freshly decoded file), and holding all T views alive at once would pin T parent buffers in memory. Peak usage here is the output array plus a single frame.

Returns:

THWCSequenceSource – An in-memory source independent of any parent.

Return type:

THWCSequenceSource

class acia.base.RotatedCropSpec[source]#

Bases: object

Specification of a rotated-rectangle crop.

The crop is described in the parent image’s pixel coordinate system. The region is straightened (de-rotated) into an axis-aligned output of shape (size[1], size[0]) == (h, w).

Variables:
  • center (tuple[float, float]) – Rectangle center as (x, y) in pixel coordinates.

  • size (tuple[int, int]) – Output size as (w, h) in pixels; both must be positive ints.

  • angle (float) – Rotation angle in degrees, counter-clockwise, following the OpenCV getRotationMatrix2D convention.

center: tuple[float, float]#
size: tuple[int, int]#
angle: float#
to_dict()[source]#

Return a plain JSON-friendly dict representation.

Returns:

dict{"center": [x, y], "size": [w, h], "angle": angle}.

Return type:

dict[str, Any]

classmethod from_dict(data)[source]#

Build a RotatedCropSpec from a plain dict.

Parameters:

data (dict[str, Any]) – A mapping as produced by to_dict().

Returns:

RotatedCropSpec – The reconstructed spec.

Return type:

RotatedCropSpec

__init__(center, size, angle)#
Parameters:
Return type:

None

class acia.base.RotatedCropSequenceSource[source]#

Bases: ImageSequenceSource, JupyterVisualizationMixin

A lazy rotated-rectangle crop view over a parent sequence.

Each frame is warped on demand via OpenCV so the rotated region is straightened and centered into an axis-aligned (h, w) output. Pixel spacing is unchanged by rotation and no frames are dropped, so pixel_size and timepoints pass through from the parent (own-wins-else-parent).

A rotated rectangle that extends past the image bounds is filled with a zero border (no crash).

Note

pixel_size pass-through is exact only for isotropic (square) pixels. For an anisotropic [y, x] pixel size, a rotation that is not a multiple of 90 degrees mixes the axes, so the reported pixel size is approximate. Frames are interpolated with INTER_LINEAR; this crops intensity images, not label/mask images (linear interpolation would blend label ids).

__init__(parent, spec)[source]#
Parameters:
get_frame(frame)[source]#

Get frame at given index.

Parameters:

frame (int)

Return type:

BaseImage

property size_t: int#
property size_h: int#
property size_w: int#
property size_c: int#
property num_channels: int#
property timepoints#

Per-frame pint Quantity of timepoints, or None if uncalibrated.

property pixel_size#

Pint length per pixel (scalar or [y, x]), or None.

class acia.base.RegisteredSequenceSource[source]#

Bases: ImageSequenceSource

A lazy drift-corrected view over a parent sequence.

Each frame is corrected on demand via acia.registration.apply_correction(), using the FrameTransform stored for that frame index (a per-position transform dict, as produced by batch-apply and persisted via acia.registration_persistence). A registration correction does not change frame dimensions, unlike a crop, so size_h/size_w/size_c/ num_channels simply delegate straight to the parent – no dimension recomputation.

on_missing decides what happens to a frame that has no stored transform (one that failed during batch-apply):

  • "warn" (default) – return it unchanged with a warning. Never a hard crash, so a segmentation/tracking notebook consuming this source can keep going even if a handful of frames never got a stored correction. Note that an uncorrected frame is off by the full accumulated drift, so in a sequence that has drifted it reads as a visible jump.

  • "nearest" – correct it with the nearest available frame’s transform instead. Drift between neighboring frames is usually far smaller than drift since the reference, so this is normally much closer to right than leaving the frame alone; it is still an approximation, and warns as such.

  • "error" – raise KeyError. For callers that would rather stop than consume a partially-corrected sequence.

Warnings are emitted once per frame index rather than once per call, so a lazy multi-pass consumer (crop -> write) does not repeat them on every pass. missing_frames lets a caller report the whole set once instead.

MISSING_POLICIES = ('warn', 'nearest', 'error')#
__init__(parent, transforms, *, on_missing='warn')[source]#
Parameters:
property missing_frames: set[int]#

Frame indices requested so far that had no stored transform.

get_frame(frame)[source]#
Parameters:

frame (int)

Return type:

BaseImage

property size_t: int#
property size_h: int#
property size_w: int#
property size_c: int#
property num_channels: int#
property timepoints#

Per-frame pint Quantity of timepoints, or None if uncalibrated.

property pixel_size#

Pint length per pixel (scalar or [y, x]), or None.

class acia.base.RGBSequenceSource[source]#

Bases: ImageSequenceSource

A lazy grayscale-to-RGB or per-channel color-composite view.

With colors=None, each frame is rendered by selecting channel’s plane, normalizing it to uint8 via acia.notebook.normalize_to_uint8(), and triplicating it across the color axis. With colors given, each channel present in colors is normalized independently, scaled by its resolved RGB color, and additively blended, clipped to [0, 255]. Colors are resolved once at construction time (via acia.colors.resolve_channel_color()), so an unknown color name or invalid hex string raises ValueError immediately rather than on first frame access. colors must not be empty – pass colors=None for grayscale mode instead. Channel indices (channel and every key of colors) are validated against each frame’s actual channel count as it is read, raising a clear ValueError rather than a bare numpy IndexError; this does not special-case sources whose frames are already RGB-like (e.g. an already-3-channel source, or chaining to_rgb() on the output of another to_rgb() call) – those are still rendered via channel/colors like any other source, with no pass-through or idempotency guarantee.

Rendering to RGB does not change the frame’s temporal/spatial extent, so size_t/size_h/size_w/pixel_size/timepoints delegate straight to the parent, mirroring RegisteredSequenceSource. size_c/num_channels are always 3 (not delegated), since the output is always an RGB image regardless of how many channels the parent has.

__init__(parent, channel=0, colors=None)[source]#
Parameters:
get_frame(frame)[source]#
Parameters:

frame (int)

Return type:

BaseImage

property size_t: int#
property size_h: int#
property size_w: int#
property size_c: int#
property num_channels: int#
property timepoints#

Per-frame pint Quantity of timepoints, or None if uncalibrated.

property pixel_size#

Pint length per pixel (scalar or [y, x]), or None.

class acia.base.SlicedSequenceSource[source]#

Bases: ImageSequenceSource, JupyterVisualizationMixin

A lazy view over a parent sequence selecting frames and cropping each.

Holds the parent source, a list of original frame indices and a trailing spatial/channel key applied to every frame’s array. Re-slicing nests another view, so composition is automatic.

__init__(parent, t_indices, spatial=())[source]#
Parameters:
get_frame(frame)[source]#

Get frame at given index.

Parameters:

frame (int)

Return type:

BaseImage

property size_t: int#
property size_h: int#
property size_w: int#
property size_c: int#
property num_channels: int#
property timepoints#

Per-frame pint Quantity of timepoints, or None if uncalibrated.

property pixel_size#

Pint length per pixel (scalar or [y, x]), or None.

class acia.base.RoISource[source]#

Bases: Iterable[Overlay], Sized

Base class for a RoI source (e.g. tiff metadata, OMERO, json, …)

class acia.base.ImageRoISource[source]#

Bases: object

Contains both, the image and the RoI Source. Provides a joint iterator

__init__(imageSource, roiSource)[source]#
Parameters:
apply_parallel(function, num_workers=None)[source]#
apply_parallel_star(function, num_workers=None)[source]#
apply(function)[source]#
apply_star(function)[source]#