Source code for acia.tracking.processor.ultrack

"""Ultrack based tracking"""

import networkx as nx
from ultrack import to_tracks_layer, track, tracks_to_zarr
from ultrack.utils import labels_to_contours

from acia.attribute import attribute_tracking
from acia.base import ImageSequenceSource, Overlay
from acia.segm.formats import overlay_from_masks

from . import TrackingProcessor
from .utils import overlay_to_masks


[docs] class UltrackTracker(TrackingProcessor): """Processor for Ultrack: https://github.com/royerlab/ultrack/tree/main"""
[docs] def __init__(self, config): """_summary_ Args: config (_type_): Ultrack configuration """ self.config = config
def __call__(self, images: ImageSequenceSource, segmentation: Overlay): image = next(iter(images)).raw height, width = image.shape[:2] mask_stack = overlay_to_masks(segmentation, height=height, width=width) detection, edges = labels_to_contours(mask_stack, sigma=4.0) # perform the tracking track( foreground=detection, edges=edges, config=self.config, overwrite=True, ) # convert back tracks_df, graph = to_tracks_layer(self.config) labels = tracks_to_zarr(self.config, tracks_df) # parse the tracking overlay from instance stack (TxHxW) tracking_ov = overlay_from_masks(labels) # create the tracklet graph tracklet_graph = nx.DiGraph() for child, parent in graph.items(): tracklet_graph.add_edge(parent, child) # compute tracking graph label_contours: dict = {} for cont in tracking_ov: label_contours[cont.label] = label_contours.get(cont.label, []) + [cont] tracking_graph = nx.DiGraph() for label, contours in label_contours.items(): sorted(contours, key=lambda c: c.frame) # print([c.frame for c in contours]) tracklet_graph.nodes[label]["start_frame"] = contours[0].frame tracklet_graph.nodes[label]["end_frame"] = contours[-1].frame tracking_graph.add_nodes_from([c.id for c in contours]) # add sequential tracks for c1, c2 in zip(contours[:-1], contours[1:], strict=False): tracking_graph.add_edge(c1.id, c2.id) # add divisions parent_labels = list(tracklet_graph.predecessors(label)) # add connection to every parent for pl in parent_labels: last_cont = label_contours[pl][-1] tracking_graph.add_edge(last_cont.id, contours[0].id) attribute_tracking(tracking_ov, tracklet_graph, tracking_graph, self) return tracking_ov, tracklet_graph, tracking_graph