Skip to content

Commit

Permalink
Merge branch 'main' into node-gt-matching
Browse files Browse the repository at this point in the history
  • Loading branch information
JoOkuma committed Oct 29, 2024
2 parents ce6c575 + 062a93e commit b4a5f79
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 8 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ Install or update [conda](https://docs.conda.io/projects/conda/en/latest/user-gu
To avoid conflicts between different packages, we recommend using conda to create an isolated environment:

```bash
conda create --name tracking -c conda-forge python=3.10 pyqt
conda activate tracking
conda create -n ultrack python=3.11 higra gurobi pytorch pyqt -c pytorch -c gurobi -c conda-forge
conda activate ultrack
pip install ultrack
```

NOTE: `gurobi` and `-c gurobi` are optional but recommended; they can be installed later, as shown below.

## Usage

**ATTENTION**: every time you need to run this software you'll have to activate this environment
**ATTENTION**: every time you need to run this software, you'll have to activate this environment

```bash
conda activate tracking
conda activate ultrack
```

Here is a basic example to get you started:
Expand Down
16 changes: 12 additions & 4 deletions examples/node_features.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
"""
This example how request for each segmentation hypotheses features and use them
to compute a custom edge weight between nodes, in this case, the cosine distance.
For this we consider a 3D image as a 2D video, it's more a didactic example than a real use case.
"""
import napari
import numpy as np
from scipy.spatial.distance import cdist
Expand All @@ -22,10 +28,12 @@ def main() -> None:
# mocking a 3D image as 2D video
image = cells3d()[:, 1] # nuclei

# simple foreground extraction
foreground = image > image.mean()
foreground = morph.opening(foreground, morph.disk(3)[None, :])
foreground = morph.closing(foreground, morph.disk(3)[None, :])

# contour as inverse of the image
contour = 1 - image / image.max()

tracker.segment(
Expand All @@ -51,14 +59,17 @@ def main() -> None:
"equivalent_diameter_area",
]

# normalizing features
df[cols] -= df[cols].mean()
df[cols] /= df[cols].std()

df_by_t = df.groupby("t")
t_max = df["t"].max()

# iterating over time and querying pair of frames
for t in range(t_max + 1):
try:
# some frames might be without nodes
source_df = df_by_t.get_group(t)
target_df = df_by_t.get_group(t + 1)
except KeyError:
Expand All @@ -70,14 +81,11 @@ def main() -> None:
source_ids = np.repeat(source_df.index.to_numpy(), len(target_df))
target_ids = np.tile(target_df.index.to_numpy(), len(source_df))

# very dense graph, not recommended, select k-nearest neighbors
# for very dense graph this not recommended because the ILP problem will be huge
tracker.add_links(sources=source_ids, targets=target_ids, weights=weights)

tracker.solve()

# for CTC use this
# tracker.to_ctc()

tracks, graph = tracker.to_tracks_layer()
segments = tracker.to_zarr()

Expand Down

0 comments on commit b4a5f79

Please sign in to comment.