Source code for ddd_pylib.tracking._points_tracking_operator
from ddd_pylib._base import PointsOperator
import numpy as np
import pandas as pd
from._tracking_base import TrackingBase
# The mainDataFrame will likely come from Napari. In this case, coordinates of points are
# expressed in pixels and the scale of the layer makes them show in the correct location.
# However, we still want the user to express the searching range or the memory in physical units
# for them to be consistent with the rest of the analysis.
# However, most tracking libraries expect:
# - the T axis to be in frames (integers) which corresponds to an uncalibrated value.
# - the spatial coordinates to be expressed in the same units as the searching range (e.g. microns)
# When comes tracking, we need to:
# - create a temporary dataframe that keeps the T column as integers AND convert the memory to frames (integers) using the calibration.
# - convert the spatial coordinates to the same units as the searching range (e.g. microns) using the calibration.
[docs]
class PointsTrackingOperator(TrackingBase, PointsOperator):
def __init__(self):
super().__init__()
def _applyToFrame(self, frameData, t, nT):
raise RuntimeError("This operator does not support frame-wise processing. Use the 'linkTracks' method instead.")
[docs]
def getPrefix(self) -> str:
return "Tracked-"
[docs]
def checkAxes(self):
if self._strategy is None:
raise ValueError("Tracking strategy has not been set.")
in_axes = set(self.getMainDataFrame().columns)
if 'T' not in in_axes:
raise ValueError("The 'T' axis is required for tracking.")
if len(in_axes.intersection({'X', 'Y'})) != 2:
raise ValueError("The minimal setup is 2D tracking and requireds both 'X' and 'Y' axes.")
[docs]
def getCalibratedDataFrame(self) -> pd.DataFrame:
df = self.getMainDataFrame().copy()
calib = self.getCalibration()
# Convert spatial coordinates to physical units
for ax in ['X', 'Y', 'Z']:
if ax in df.columns:
df[ax] = df[ax] * calib['scale'][ax]
return df
def _setResultFromCalibratedDataFrame(self, df: pd.DataFrame):
calib = self.getCalibration()
# Convert spatial coordinates back to pixel units
for ax in ['X', 'Y', 'Z']:
if ax in df.columns:
df[ax] = df[ax] / calib['scale'][ax]
self._result = df
def _run(self):
self.checkAxes()
s = self.getStrategy()
s._updateOperator(self)
s.run()
linked_df = s.getResult()
self._setResultFromCalibratedDataFrame(linked_df)
yield 0