Skip to content

Commit aeeba18

Browse files
committed
Now, also mitosis are detected, if daughters appear in the future with a timegap > 0. It is similar to the fiji plugin implementation
1 parent 6873f90 commit aeeba18

1 file changed

Lines changed: 51 additions & 23 deletions

File tree

  • ctc_metrics/metrics/biological

ctc_metrics/metrics/biological/bc.py

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ def get_ids_that_ends_with_split(
2121
counts = counts[parents > 0]
2222
parents = parents[parents > 0]
2323
ends_with_split = parents[counts > 1]
24-
print("ends_with_split:", ends_with_split)
2524
return ends_with_split
2625

2726

@@ -54,8 +53,10 @@ def is_matching(
5453
mapped_comp: list,
5554
ref_children: np.ndarray,
5655
comp_children: np.ndarray,
57-
tr: int,
58-
tc: int
56+
t_parent_end_ref: int,
57+
t_parent_end_comp: int,
58+
t_child_start_ref: list,
59+
t_child_start_comp: list,
5960
):
6061
"""
6162
Checks if the reference and the computed track match.
@@ -67,8 +68,10 @@ def is_matching(
6768
mapped_comp: The matched labels of the result masks.
6869
ref_children: The children ids of the reference track.
6970
comp_children: The children ids of the computed track.
70-
tr: The frame of the reference track end.
71-
tc: The frame of the computed track end.
71+
t_parent_end_ref: The frame of the reference track end.
72+
t_parent_end_comp: The frame of the computed track end.
73+
t_child_start_ref: The frame of the reference track start.
74+
t_child_start_comp: The frame of the computed track start.
7275
7376
Returns:
7477
True if the reference and the computed track match, False otherwise.
@@ -77,21 +80,33 @@ def is_matching(
7780
if len(ref_children) != len(comp_children):
7881
return False
7982
# Compare parents
80-
t1, _ = min(tr, tc), max(tr, tc)
81-
mr, mc = mapped_ref[t1], mapped_comp[t1]
83+
t_start = min(t_parent_end_ref, t_parent_end_comp)
84+
mr, mc = mapped_ref[t_start], mapped_comp[t_start]
8285
if np.sum(mc == id_comp) < 1 or np.sum(mr == id_ref) != 1:
8386
return False
8487
ind = np.argwhere(mr == id_ref).squeeze()
8588
if mc[ind] != id_comp:
8689
return False
87-
# # Compare children ### WHAT IS A CORRECT DETECTED MITOSIS?
88-
# mr, mc = np.concatenate(mapped_ref[t2 + 1]), np.concatenate(mapped_comp[t2 + 1])
89-
# if not np.all(np.isin(comp_children, mc)):
90-
# return False
91-
# if not np.all(np.isin(mr[np.isin(mc, comp_children)], ref_children)):
92-
# return False
90+
# Compare children
91+
# Iterate over all GT ids and check if the first detection is matched to the correct reference children
92+
matched_children = []
93+
for i, t_ref in zip(ref_children, t_child_start_ref):
94+
for j, t_comp in zip(comp_children, t_child_start_comp):
95+
t_max = max(t_ref, t_comp)
96+
if i in mapped_ref[t_max] and j in mapped_comp[t_max]:
97+
ind = mapped_ref[t_max].index(i)
98+
if mapped_comp[t_max][ind] == j:
99+
# There is a match!
100+
if j not in matched_children:
101+
matched_children.append(j)
102+
break
103+
104+
if len(matched_children) != len(ref_children):
105+
return False
106+
93107
return True
94108

109+
95110
def raw_division_metrics(
96111
comp_tracks: np.ndarray,
97112
ref_tracks: np.ndarray,
@@ -101,7 +116,7 @@ def raw_division_metrics(
101116
):
102117
"""
103118
Computes number of true positives, false positives, and false negatives for divisions.
104-
119+
105120
Args:
106121
comp_tracks: The result tracks. A (n,4) numpy ndarray with columns:
107122
- label
@@ -137,36 +152,49 @@ def raw_division_metrics(
137152
ends_with_split_comp = get_ids_that_ends_with_split(comp_tracks)
138153
t_comp = np.asarray([comp_tracks[comp_tracks[:, 0] == comp][0, 2]
139154
for comp in ends_with_split_comp])
140-
141-
# If there are no divisions in the reference
155+
156+
# If there are no divisions in the reference
142157
if len(ends_with_split_ref) == 0:
143158
return (0, len(ends_with_split_comp), 0)
144-
159+
145160
# If there are no divisions in the computed result
146161
if len(ends_with_split_comp) == 0:
147162
return (0, 0, len(ends_with_split_ref))
148-
163+
149164
# Find all matches between reference and computed branching events (mitosis)
150165
matches = []
151-
for comp, tc in zip(ends_with_split_comp, t_comp):
166+
for comp, t_parent_end_start in zip(ends_with_split_comp, t_comp):
152167
# Find potential matches
153-
pot_matches = np.abs(t_ref - tc) <= i
168+
pot_matches = np.abs(t_ref - t_parent_end_start) <= i
154169
if len(pot_matches) == 0:
155170
continue
156171
comp_children = comp_tracks[comp_tracks[:, 3] == comp][:, 0]
172+
t_child_start_comp = []
173+
for j in comp_children:
174+
t = comp_tracks[comp_tracks[:, 0] == j][0, 1]
175+
t_child_start_comp.append(t)
157176
# Evaluate potential matches
158-
for ref, tr in zip(
177+
for ref, t_parent_end_ref in zip(
159178
ends_with_split_ref[pot_matches],
160179
t_ref[pot_matches]
161180
):
162181
ref_children = ref_tracks[ref_tracks[:, 3] == ref][:, 0]
182+
t_child_start_ref = []
183+
for j in ref_children:
184+
t = ref_tracks[ref_tracks[:, 0] == j][0, 1]
185+
t_child_start_ref.append(t)
163186
if is_matching(
164-
comp, ref, mapped_ref, mapped_comp, ref_children,
165-
comp_children, tr, tc
187+
comp, ref,
188+
mapped_ref, mapped_comp,
189+
ref_children, comp_children,
190+
t_parent_end_ref, t_parent_end_start,
191+
t_child_start_ref,
192+
t_child_start_comp,
166193
):
167194
matches.append((ref, comp))
168195
return (len(matches), len(ends_with_split_comp) - len(matches), len(ends_with_split_ref) - len(matches))
169196

197+
170198
def bc(
171199
tp: int,
172200
fp: int,

0 commit comments

Comments
 (0)