Source code for acia.tracking.processor.pyuat
"""PyUAT based tracking"""
import gzip
import tempfile
import time
import warnings
from pathlib import Path
from uatrack.config import setup_assignment_generators
from uatrack.core import simpleTracking
from uatrack.utils import extract_single_cell_information, save_tracking
from acia.attribute import attribute_tracking
from acia.base import ImageSequenceSource, Overlay
from acia.segm.formats import overlay_from_masks
from acia.tracking.formats import parse_simple_tracking
from acia.tracking.processor.utils import overlay_to_masks
from . import TrackingProcessor
TRACKING_CONFIGURATIONS = ["NN", "FO", "FO+G", "FO+O", "FO+DD", "FO+G+O+DD"]
[docs]
class PyUATTracker(TrackingProcessor):
"""Processor for PyUAT: https://arxiv.org/abs/2503.21914"""
[docs]
def __init__(
self,
tracking_configuration: str,
subsampling_factor=1,
num_particles=1,
num_cores=1,
max_num_hypotheses=1,
cutOff=-1,
max_num_solutions=1,
mip_method="CBC",
):
"""
Args:
tracking_configuration (str): PyUAT tracking configuration
"""
if tracking_configuration not in TRACKING_CONFIGURATIONS:
raise ValueError(
f"'{tracking_configuration}' is not a valid tracking configuration. Pleas one of {TRACKING_CONFIGURATIONS}!"
)
self.config = tracking_configuration
self.subsampling_factor = subsampling_factor
self.num_particles = num_particles
self.num_cores = num_cores
self.max_num_hypotheses = max_num_hypotheses
self.cutOff = cutOff
self.max_num_solutions = max_num_solutions
self.mip_method = mip_method
if mip_method != "GRB":
warnings.warn(
"You are not using Gurobi! Please install gurobi and specify 'GRB' as optimizer for a tremendous speedup!",
stacklevel=2,
)
def __call__(self, images: ImageSequenceSource, segmentation: Overlay):
print("Extract single-cell information...")
df, all_detections = extract_single_cell_information(segmentation)
print("Setup assignment generators...")
assignment_generators = setup_assignment_generators(
df, self.subsampling_factor, self.config
)
print("Perform tracking...")
# start tracking
start = time.time()
res = simpleTracking(
df,
assignment_generators,
self.num_particles,
num_cores=self.num_cores,
max_num_hypotheses=self.max_num_hypotheses,
cutOff=self.cutOff,
max_num_solutions=self.max_num_solutions,
mip_method=self.mip_method, # use "GRB" if you have gurobi installed
)
end = time.time()
print("time for tracking", end - start)
with tempfile.TemporaryDirectory() as td:
output_file = Path(td) / "simpleTracking.json.gz"
save_tracking(res[0], all_detections, output_file)
# read the tracking result
with gzip.open(output_file) as input_file:
tracking_overlay, tracking_graph = parse_simple_tracking(
input_file.read().decode("utf-8")
)
# Convert from contour based overlay to a mask based overlay
height, width = images.get_frame(0).raw.shape[:2]
mask_stack = overlay_to_masks(tracking_overlay, height, width)
tracking_ov_new = overlay_from_masks(mask_stack)
attribute_tracking(tracking_ov_new, None, tracking_graph, self)
# TODO: create tracklet graph
return tracking_ov_new, None, tracking_graph