Skip to content

Commit

Permalink
Fix bug in is_valid_lineage; daughters can be < parent. (#88)
Browse files Browse the repository at this point in the history
* Test parent label > daughter labels.

* No need to see if daughter in all_cells.

If it is in the lineage (checked for), then it will be removed from all_cells in due time.

* Warn for all mistakes and return True if

* If not in all cells, don't remove it from the set.

* Continue instead of return, keep the short circuit.

* Update version to 0.5.4

* Clarify warnings.
  • Loading branch information
willgraf authored Nov 19, 2021
1 parent 0b6a369 commit 52974c7
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 16 deletions.
41 changes: 26 additions & 15 deletions deepcell_tracking/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,13 +488,16 @@ def is_valid_lineage(y, lineage):
all_cells = np.unique(y)
all_cells = set([c for c in all_cells if c])

is_valid = True

# every lineage should have valid fields
for cell_label, cell_lineage in lineage.items():
# Get last frame of parent
if cell_label not in all_cells:
warnings.warn('Cell {} not found in the label image.'.format(
cell_label))
return False
is_valid = False
continue

# any cells leftover are missing lineage
all_cells.remove(cell_label)
Expand All @@ -505,28 +508,33 @@ def is_valid_lineage(y, lineage):
frames = list(y_index)
if frames != cell_lineage['frames']:
warnings.warn('Cell {} has invalid frames'.format(cell_label))
return False
is_valid = False
continue # no need to test further

last_parent_frame = cell_lineage['frames'][-1]

for daughter in cell_lineage['daughters']:
if daughter not in all_cells or daughter not in lineage:
warnings.warn('lineage {} has invalid daughters: {}'.format(
cell_label, cell_lineage['daughters']))
return False
if daughter not in lineage:
warnings.warn('Lineage {} has daughter {} not in lineage'.format(
cell_label, daughter))
is_valid = False
continue # no need to test further

# get first frame of daughter
try:
first_daughter_frame = lineage[daughter]['frames'][0]
except IndexError: # frames is empty?
warnings.warn('Daughter {} has no frames'.format(daughter))
return False
is_valid = False
continue # no need to test further

# Check that daughter's start frame is one larger than parent end frame
if first_daughter_frame - last_parent_frame != 1:
warnings.warn('lineage {} has daughter {} before parent.'.format(
cell_label, daughter))
return False
warnings.warn('Lineage {} has daughter {} in a '
'non-subsequent frame.'.format(
cell_label, daughter))
is_valid = False
continue # no need to test further

# TODO: test parent in lineage
parent = cell_lineage.get('parent')
Expand All @@ -536,28 +544,31 @@ def is_valid_lineage(y, lineage):
except KeyError:
warnings.warn('Parent {} is not present in the lineage'.format(
cell_lineage['parent']))
return False
is_valid = False
continue # no need to test further
try:
last_parent_frame = parent_lineage['frames'][-1]
first_daughter_frame = cell_lineage['frames'][0]
except IndexError: # frames is empty?
warnings.warn('Cell {} has no frames'.format(parent))
return False
is_valid = False
continue # no need to test further
# Check that daughter's start frame is one larger than parent end frame
if first_daughter_frame - last_parent_frame != 1:
warnings.warn(
'Cell {} ends in frame {} but daughter {} first '
'appears in frame {}.'.format(
parent, last_parent_frame, cell_label,
first_daughter_frame))
return False
is_valid = False
continue # no need to test further

if all_cells: # all cells with lineages should be removed
warnings.warn('Cells missing their lineage: {}'.format(
list(all_cells)))
return False
is_valid = False

return True # all cell lineages are valid!
return is_valid # if unchanged, all cell lineages are valid!


def get_image_features(X, y, appearance_dim=32):
Expand Down
11 changes: 11 additions & 0 deletions deepcell_tracking/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,17 @@ def test_is_valid_lineage(self):
bad_lineage[daughter_labels[0]]['frames'] = []
assert not utils.is_valid_lineage(movie, bad_lineage)

# parent ID > daughters ID is OK
new_parent = max(np.unique(movie)) + 2
relabeled_movie = np.where(movie == parent_label, new_parent, movie)
relabeled_lineage = copy.deepcopy(lineage)
relabeled_lineage[new_parent] = lineage[parent_label]
del relabeled_lineage[parent_label]
for daughter in relabeled_lineage[new_parent]['daughters']:
if relabeled_lineage[daughter]['parent'] == parent_label:
relabeled_lineage[daughter]['parent'] = new_parent
assert utils.is_valid_lineage(relabeled_movie, relabeled_lineage)

def test_get_image_features(self):
num_labels = 3
y = get_annotated_image(num_labels=num_labels, sequential=True)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
readme = f.read()


VERSION = '0.5.3'
VERSION = '0.5.4'
NAME = 'DeepCell_Tracking'
DESCRIPTION = 'Tracking cells and lineage with deep learning.'
LICENSE = 'LICENSE'
Expand Down

0 comments on commit 52974c7

Please sign in to comment.