Skip to content

Commit

Permalink
Add export to trackmate format (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoOkuma authored Aug 26, 2023
1 parent 64be2b7 commit 1f854d4
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 2 deletions.
35 changes: 35 additions & 0 deletions NOTES
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# REFACTOR:
- merge multiple solver classes methods into constructor to make a single deeper function

# TODO:
- IMPORTANT: free nodes after each hierarchy insertation to database and measure performance.
- IMPORTANT: refactor widget to use a tab per option (segment, link, track)
- add warning when DB already contains data.
- create homepage/docs.
- document config
- document database
- option to lock segmentations from hypothesis viz widget

# NOTES:
- heuristic optimizer:
- add monte-carlo (probabilist) moves into local search function
- local search by removing a node and trying to add its overlapping nodes

- slurm:
- segment: 1hr 30min, 790 jobs
- link: 30min, 789 jobs
- track 1st: 2hr 30min, 8 jobs of 100 time points + overlap
- track 2nd: 2hr, 8 jobs of 100 time points + overlap
- export: 20min
- total: about 7 hours
- NOTES:
- fix window overlap sql solution update by adding parents only when it already exists on solution
- segment step memory usage must be improved, with Daxi dataset it's using about 100GB per frame
- tracks should be divided into smaller chunks
- reduce tracking model build time with vector variables

# ARTICLE:
- experiments comparing tracking results from essemble of connected components, watershed, cellpose, stardist vs their accuracy alone;
- experiments comparing results from binary contour (their own algorithm post processing) vs contour obtained from network output directly;
- cell-tracking challenge benchmark;
- qualitative results our dataset and jan funke datasets;
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pre-commit = "^3.2.2"
pytest-qt = "^4.2.0"
asv = "^0.5.1"
"testing.postgresql" = "^1.3.0"
pytrackmate = {git = "https://github.com/hadim/pytrackmate.git"}

[tool.poetry.extras]
flow = [
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ deps =
pyqt5
poetry
testing.postgresql
git+https://github.com/hadim/pytrackmate.git
commands =
pytest -v --color=yes --cov=ultrack --cov-report=xml --durations=15 --ignore=ultrack/widgets

Expand Down
1 change: 1 addition & 0 deletions ultrack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from ultrack.config.config import MainConfig, load_config
from ultrack.core.export.ctc import to_ctc
from ultrack.core.export.trackmate import to_trackmate
from ultrack.core.export.tracks_layer import to_tracks_layer
from ultrack.core.export.zarr import tracks_to_zarr
from ultrack.core.linking.processing import link
Expand Down
1 change: 1 addition & 0 deletions ultrack/analysis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def get_subgraph(
compressed_df["track_id"].to_numpy(dtype=int),
compressed_df["parent_track_id"].to_numpy(dtype=int),
)
roots = np.asarray(roots, dtype=int)

subforest = []
for root in roots:
Expand Down
14 changes: 13 additions & 1 deletion ultrack/cli/_test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def _run_command(command_and_args: List[str]) -> None:
try:
main(command_and_args)
except SystemExit as exit:
assert exit.code == 0
assert exit.code == 0, f"{command_and_args} failed with exit code {exit.code}"


@pytest.mark.usefixtures("zarr_dataset_paths")
Expand Down Expand Up @@ -105,6 +105,18 @@ def test_ctc_export(self, instance_config_path: str, tmp_path: Path) -> None:
]
)

def test_trackmate_export(self, instance_config_path: str, tmp_path: Path) -> None:
_run_command(
[
"export",
"trackmate",
"-cfg",
instance_config_path,
"-o",
str(tmp_path / "tracks.xml"),
]
)

def test_zarr_napari_export(
self,
instance_config_path: str,
Expand Down
25 changes: 24 additions & 1 deletion ultrack/cli/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
tuple_callback,
)
from ultrack.config import MainConfig
from ultrack.core.export import to_ctc, to_tracks_layer, tracks_to_zarr
from ultrack.core.export import to_ctc, to_trackmate, to_tracks_layer, tracks_to_zarr
from ultrack.core.export.utils import maybe_overwrite_path
from ultrack.imgproc.measure import tracks_properties

Expand Down Expand Up @@ -162,10 +162,33 @@ def zarr_napari_cli(
tracks_w_measures.to_csv(tracks_path, index=False)


@click.command("trackmate")
@click.option(
"--output-path",
"-o",
required=True,
type=click.Path(path_type=Path),
show_default=True,
help="TrackMate XML output path.",
)
@config_option()
@overwrite_option()
def trackmate_cli(
config: MainConfig,
output_path: Path,
overwrite: bool,
) -> None:
"""
Exports tracking results to TrackMate XML format.
"""
to_trackmate(config, output_path, overwrite)


@click.group("export")
def export_cli() -> None:
"""Exports tracking and segmentation results to selected format."""


export_cli.add_command(ctc_cli)
export_cli.add_command(trackmate_cli)
export_cli.add_command(zarr_napari_cli)
1 change: 1 addition & 0 deletions ultrack/core/export/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from ultrack.core.export.ctc import to_ctc
from ultrack.core.export.trackmate import to_trackmate
from ultrack.core.export.tracks_layer import to_tracks_layer
from ultrack.core.export.zarr import tracks_to_zarr
37 changes: 37 additions & 0 deletions ultrack/core/export/_test/test_trackmate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from pathlib import Path

import numpy as np
import pandas as pd
from pytrackmate import trackmate_peak_import

from ultrack.core.database import NO_PARENT
from ultrack.core.export.trackmate import tracks_layer_to_trackmate


def test_trackmate_writer(tmp_path: Path) -> None:
tracks_outpath = tmp_path / "tracks.xml"

tracks_df = pd.DataFrame(
{
"id": [1, 2, 3, 4],
"parent_id": [NO_PARENT, 1, 2, 2],
"track_id": [1, 1, 2, 3],
"t": [0, 1, 2, 2],
"z": [0, 0, 0, 0],
"y": [10, 20, 30, 10],
"x": [1, 2, 3, 1],
}
)

xml_str = tracks_layer_to_trackmate(tracks_df)
with open(tracks_outpath, "w") as f:
f.write(xml_str)

trackmate_df = trackmate_peak_import(tracks_outpath)
print(trackmate_df)

assert trackmate_df.shape[0] == tracks_df.shape[0]

np.testing.assert_allclose(
tracks_df[["t", "z", "y", "x"]], trackmate_df[["t_stamp", "z", "y", "x"]]
)
Loading

0 comments on commit 1f854d4

Please sign in to comment.