trackmate
sleap_io.io.trackmate
¶
Read TrackMate CSV exports into sleap-io data structures.
TrackMate (ImageJ/Fiji) exports tracking results as three CSV files per video:
*_spots.csv— Individual spot detections (required).*_edges.csv— Frame-to-frame linkages with assignment cost (optional).*_tracks.csv— Track-level summary statistics (not used).
All CSVs have 4 header rows (field names, descriptions, abbreviations, units) followed by data rows.
See Also
https://imagej.net/plugins/trackmate/
Functions:
| Name | Description |
|---|---|
is_trackmate_file |
Check if a CSV file is a TrackMate spots export. |
read_trackmate_csv |
Load TrackMate CSV exports into a |
Attributes:
| Name | Type | Description |
|---|---|---|
TYPE_CHECKING |
Returns True when the argument is true, False otherwise. |
|
__cached__ |
str(object='') -> str |
|
__doc__ |
str(object='') -> str |
|
__file__ |
str(object='') -> str |
|
__name__ |
str(object='') -> str |
|
__package__ |
str(object='') -> str |
TYPE_CHECKING = False
module-attribute
¶
Returns True when the argument is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.
__cached__ = '/home/runner/work/sleap-io/sleap-io/sleap_io/io/__pycache__/trackmate.cpython-313.pyc'
module-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to 'utf-8'. errors defaults to 'strict'.
__doc__ = 'Read TrackMate CSV exports into sleap-io data structures.\n\nTrackMate (ImageJ/Fiji) exports tracking results as three CSV files per video:\n\n- ``*_spots.csv`` — Individual spot detections (required).\n- ``*_edges.csv`` — Frame-to-frame linkages with assignment cost (optional).\n- ``*_tracks.csv`` — Track-level summary statistics (not used).\n\nAll CSVs have **4 header rows** (field names, descriptions, abbreviations,\nunits) followed by data rows.\n\nSee Also:\n https://imagej.net/plugins/trackmate/\n'
module-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to 'utf-8'. errors defaults to 'strict'.
__file__ = '/home/runner/work/sleap-io/sleap-io/sleap_io/io/trackmate.py'
module-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to 'utf-8'. errors defaults to 'strict'.
__name__ = 'sleap_io.io.trackmate'
module-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to 'utf-8'. errors defaults to 'strict'.
__package__ = 'sleap_io.io'
module-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to 'utf-8'. errors defaults to 'strict'.
is_trackmate_file(path)
¶
Check if a CSV file is a TrackMate spots export.
Reads the first line and checks for the TrackMate column signature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Path to a CSV file. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in sleap_io/io/trackmate.py
def is_trackmate_file(path: str | Path) -> bool:
"""Check if a CSV file is a TrackMate spots export.
Reads the first line and checks for the TrackMate column signature.
Args:
path: Path to a CSV file.
Returns:
``True`` if the file looks like a TrackMate spots CSV.
"""
try:
with open(path, newline="") as f:
first_line = f.readline().strip()
cols = first_line.split(",")
return tuple(cols[: len(_SPOTS_SIGNATURE)]) == _SPOTS_SIGNATURE
except Exception:
return False
read_trackmate_csv(spots_path, edges_path=None, video=None)
¶
Load TrackMate CSV exports into a Labels object.
The spots CSV is required. The edges CSV is optional but provides
per-link tracking_score (from TrackMate's LINK_COST).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spots_path
|
str | Path
|
Path to the |
required |
edges_path
|
str | Path | None
|
Path to the |
None
|
video
|
Video | str | Path | None
|
Video to associate with centroids. Can be a |
None
|
Returns:
| Type | Description |
|---|---|
Labels
|
A |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the spots CSV does not exist. |
ValueError
|
If the spots CSV does not have the expected TrackMate column signature. |
Source code in sleap_io/io/trackmate.py
def read_trackmate_csv(
spots_path: str | Path,
edges_path: str | Path | None = None,
video: "Video | str | Path | None" = None,
) -> "Labels":
"""Load TrackMate CSV exports into a ``Labels`` object.
The spots CSV is required. The edges CSV is optional but provides
per-link ``tracking_score`` (from TrackMate's ``LINK_COST``).
Args:
spots_path: Path to the ``*_spots.csv`` file.
edges_path: Path to the ``*_edges.csv`` file. If ``None``, attempts
to auto-detect a sibling ``_edges.csv`` alongside the spots file.
video: Video to associate with centroids. Can be a ``Video`` object,
a string/path to a video file, or ``None`` (auto-detects a
sibling ``.tif`` file).
Returns:
A ``Labels`` object with ``centroids``, ``tracks``, and optionally
``videos`` populated.
Raises:
FileNotFoundError: If the spots CSV does not exist.
ValueError: If the spots CSV does not have the expected TrackMate
column signature.
"""
from sleap_io.model.centroid import PredictedCentroid
from sleap_io.model.instance import Track
from sleap_io.model.labeled_frame import LabeledFrame
from sleap_io.model.labels import Labels
from sleap_io.model.video import Video as VideoClass
spots_path = Path(spots_path)
if not spots_path.exists():
raise FileNotFoundError(f"Spots CSV not found: {spots_path}")
# --- Auto-detect sibling files ---
if edges_path is not None:
edges_path = Path(edges_path)
else:
edges_path = _find_sibling(spots_path, "_edges")
video_obj: VideoClass | None = None
if video is not None:
if isinstance(video, (str, Path)):
video_obj = VideoClass(filename=str(video))
else:
video_obj = video
else:
tif_path = _find_sibling(spots_path, ".tif")
if tif_path is not None:
video_obj = VideoClass(filename=str(tif_path), open_backend=False)
# --- Parse edges (if available) ---
target_to_cost: dict[int, float] = {}
if edges_path is not None and edges_path.exists():
target_to_cost = _parse_edges(edges_path)
# --- Parse spots CSV ---
with open(spots_path, newline="") as f:
reader = csv.reader(f)
# Read header row to find column indices.
header = next(reader)
if tuple(header[: len(_SPOTS_SIGNATURE)]) != _SPOTS_SIGNATURE:
raise ValueError(
f"Not a TrackMate spots CSV. Expected columns starting with "
f"{_SPOTS_SIGNATURE}, got {tuple(header[:6])}."
)
col = {name: header.index(name) for name in header}
# Skip remaining header rows.
for _ in range(_HEADER_ROWS - 1):
next(reader, None)
# First pass: collect data rows and unique track IDs.
rows: list[list[str]] = []
track_ids: set[int] = set()
for row in reader:
if not row:
continue
rows.append(row)
tid = row[col["TRACK_ID"]]
if tid:
track_ids.add(int(tid))
# --- Build Track objects ---
track_map: dict[int, Track] = {}
for tid in sorted(track_ids):
track_map[tid] = Track(name=f"Track_{tid}")
tracks = list(track_map.values())
# --- Build PredictedCentroid objects ---
frame_centroids: dict[int, list[PredictedCentroid]] = {}
for row in rows:
spot_id = int(row[col["ID"]])
tid_str = row[col["TRACK_ID"]]
x = float(row[col["POSITION_X"]])
y = float(row[col["POSITION_Y"]])
z_val = float(row[col["POSITION_Z"]]) if "POSITION_Z" in col else 0.0
z = z_val if z_val != 0.0 else None
frame_idx = int(float(row[col["FRAME"]]))
score = float(row[col["QUALITY"]])
track = track_map.get(int(tid_str)) if tid_str else None
tracking_score = target_to_cost.get(spot_id)
label = row[col["LABEL"]] if "LABEL" in col else f"ID{spot_id}"
centroid = PredictedCentroid(
x=x,
y=y,
z=z,
track=track,
tracking_score=tracking_score,
score=score,
name=label,
source="trackmate",
)
# Collect per-frame centroids for distribution to LabeledFrames
frame_centroids.setdefault(frame_idx, []).append(centroid)
# --- Assemble Labels ---
videos = [video_obj] if video_obj is not None else []
labeled_frames = []
for fidx, cents in sorted(frame_centroids.items()):
lf = LabeledFrame(video=video_obj, frame_idx=fidx)
lf.centroids.extend(cents)
labeled_frames.append(lf)
labels = Labels(videos=videos, tracks=tracks, labeled_frames=labeled_frames)
labels.provenance["filename"] = str(spots_path)
return labels