epicure.laptrack_overlaps

  1"""
  2Tracking with laptrack package
  3
  4Inspired from example https://github.com/yfukai/laptrack/blob/main/docs/examples/cell_segmentation.ipynb
  5"""
  6
  7import numpy as np
  8import pandas as pd
  9from skimage.measure import regionprops_table
 10import laptrack
 11from laptrack import OverLapTrack
 12#from laptrack import datasets
 13import epicure.Utils as ut
 14from packaging.version import Version
 15
 16
 17class LaptrackOverlaps():
 18
 19    def __init__(self, track, epic):
 20        self.splitting_cost = 1
 21        self.cost_cutoff = 0.9
 22        self.merging_cost = 1
 23        self.track = track
 24        self.epicure = epic
 25        self.inspecting = False
 26        self.suggesting = False
 27        ## to handle difference in laptrack versions
 28        self.version_over = Version(laptrack.__version__) >= Version("0.17.0")
 29        
 30
 31    def twoframes_track(self, img_labels, labels):
 32        """ Do track between two frames, only track label """
 33        #start_time = time.time()
 34        track_df, split_df, merge_df = self.perform_track( img_labels )
 35        #show_info("Performed in "+"{:.3f}".format((time.time()-start_time)/60)+" min")
 36        
 37        track_ids = [None]*len(labels)
 38        ## look for track id associated with label
 39        for i, row in track_df.iterrows():
 40            frame = int(row["frame"])
 41            if frame == 1:
 42                tid = int(row["track_id"])
 43                curlabel = int(row["label"])
 44                ind = labels.index(curlabel)
 45                track_ids[ind] = tid
 46
 47        tracklabels = [None]*len(labels)
 48        ## look for cell label associated with track_id in the first frame, if any
 49        for i, row in track_df.iterrows():
 50            frame = int(row["frame"])
 51            tid = int(row["track_id"])
 52            if (tid in track_ids) and (frame==0):
 53                ind = track_ids.index(tid)
 54                label = int(row["label"])
 55                tracklabels[ind] = label 
 56        #show_info("Finished in "+"{:.3f}".format((time.time()-start_time)/60)+" min")
 57        return tracklabels
 58
 59
 60    def perform_track(self, labels):
 61        """ Do tracking with laptrack module """
 62
 63        ## handling eventual missing (empty) frame:
 64        ind = []
 65        for i, lab in enumerate(labels):
 66            if len(np.unique(lab)) == 1:
 67                ind.append(i)
 68        labels = [ lab for i, lab in enumerate(labels) if i not in ind]
 69
 70        if self.version_over:
 71            ol = OverLapTrack(
 72                cutoff=self.cost_cutoff,
 73                metric_coefs=(1.0, 0.0, -1.0, 0.0, 0.0),
 74                #gap_closing_metric_coefs=(1.0, -1.0, 0.0, 0.0, 0.0),
 75                #gap_closing_max_frame_count=1,
 76                gap_closing_cutoff=False,
 77                merging_cutoff=self.merging_cost,
 78                merging_metric_coefs=(1.0, 0.0, 0.0, -1.0, 0.0),
 79                splitting_cutoff=self.splitting_cost,
 80                splitting_metric_coefs=(1.0, 0.0, 0.0, 0.0, -1.0),
 81            )
 82        else:
 83            ol = OverLapTrack(
 84                track_cost_cutoff=self.cost_cutoff,
 85                track_dist_metric_coefs=(1.0, 0.0, -1.0, 0.0, 0.0),
 86                #gap_closing_dist_metric_coefs=(1.0, -1.0, 0.0, 0.0, 0.0),
 87                #gap_closing_max_frame_count=1,
 88                gap_closing_cost_cutoff=False,
 89                merging_cost_cutoff=self.merging_cost,
 90                merging_dist_metric_coefs=(1.0, 0.0, 0.0, -1.0, 0.0),
 91                splitting_cost_cutoff=self.splitting_cost,
 92                splitting_dist_metric_coefs=(1.0, 0.0, 0.0, 0.0, -1.0),
 93            )
 94        
 95        track_df, split_df, merge_df = ol.predict_overlap_dataframe(labels)
 96        ## handle eventual missing frames
 97        track_df = track_df.reset_index()
 98        track_df["frame"] += np.searchsorted(sorted(ind), track_df["frame"], side='right')
 99
100        track_df = track_df.reset_index()
101        return track_df, split_df, merge_df
102
103    def track_overlaps(self, labels):
104        """ Track all movie with laptrack overlap method """
105        ut.napari_info("Starting tracking with laptrack Overlap...")
106        return self.perform_track( labels )
107
108
109    def inspect_oneframe(self, graph, trackdf):
110        for track in np.unique(trackdf["track_id"]):
111            tr = trackdf[trackdf["track_id"] == track]
112            ## track is only on one frame, suspect
113            if len(np.unique(tr["frame"])) == 1:
114                # trackid + 1 as trackid starts as 0
115                pos = (tr.iloc[0]["frame"], int(tr.iloc[0]["centroid-0"]), int(tr.iloc[0]["centroid-1"]))
116                self.epicure.inspecting.add_event( pos, track+1, "tracking" )
117                if self.track.suggesting:
118                    if track in graph.keys():
119                        sisters = []
120                        refval = graph[track][0]
121                        for key, val in graph.items():
122                            if val[0] == refval:
123                                sisters.append( key )
124                        if len(sisters) == 2:
125                            for sis in sisters:
126                                self.epicure.add_suggestion( sis+1, refval+1 )
class LaptrackOverlaps:
 18class LaptrackOverlaps():
 19
 20    def __init__(self, track, epic):
 21        self.splitting_cost = 1
 22        self.cost_cutoff = 0.9
 23        self.merging_cost = 1
 24        self.track = track
 25        self.epicure = epic
 26        self.inspecting = False
 27        self.suggesting = False
 28        ## to handle difference in laptrack versions
 29        self.version_over = Version(laptrack.__version__) >= Version("0.17.0")
 30        
 31
 32    def twoframes_track(self, img_labels, labels):
 33        """ Do track between two frames, only track label """
 34        #start_time = time.time()
 35        track_df, split_df, merge_df = self.perform_track( img_labels )
 36        #show_info("Performed in "+"{:.3f}".format((time.time()-start_time)/60)+" min")
 37        
 38        track_ids = [None]*len(labels)
 39        ## look for track id associated with label
 40        for i, row in track_df.iterrows():
 41            frame = int(row["frame"])
 42            if frame == 1:
 43                tid = int(row["track_id"])
 44                curlabel = int(row["label"])
 45                ind = labels.index(curlabel)
 46                track_ids[ind] = tid
 47
 48        tracklabels = [None]*len(labels)
 49        ## look for cell label associated with track_id in the first frame, if any
 50        for i, row in track_df.iterrows():
 51            frame = int(row["frame"])
 52            tid = int(row["track_id"])
 53            if (tid in track_ids) and (frame==0):
 54                ind = track_ids.index(tid)
 55                label = int(row["label"])
 56                tracklabels[ind] = label 
 57        #show_info("Finished in "+"{:.3f}".format((time.time()-start_time)/60)+" min")
 58        return tracklabels
 59
 60
 61    def perform_track(self, labels):
 62        """ Do tracking with laptrack module """
 63
 64        ## handling eventual missing (empty) frame:
 65        ind = []
 66        for i, lab in enumerate(labels):
 67            if len(np.unique(lab)) == 1:
 68                ind.append(i)
 69        labels = [ lab for i, lab in enumerate(labels) if i not in ind]
 70
 71        if self.version_over:
 72            ol = OverLapTrack(
 73                cutoff=self.cost_cutoff,
 74                metric_coefs=(1.0, 0.0, -1.0, 0.0, 0.0),
 75                #gap_closing_metric_coefs=(1.0, -1.0, 0.0, 0.0, 0.0),
 76                #gap_closing_max_frame_count=1,
 77                gap_closing_cutoff=False,
 78                merging_cutoff=self.merging_cost,
 79                merging_metric_coefs=(1.0, 0.0, 0.0, -1.0, 0.0),
 80                splitting_cutoff=self.splitting_cost,
 81                splitting_metric_coefs=(1.0, 0.0, 0.0, 0.0, -1.0),
 82            )
 83        else:
 84            ol = OverLapTrack(
 85                track_cost_cutoff=self.cost_cutoff,
 86                track_dist_metric_coefs=(1.0, 0.0, -1.0, 0.0, 0.0),
 87                #gap_closing_dist_metric_coefs=(1.0, -1.0, 0.0, 0.0, 0.0),
 88                #gap_closing_max_frame_count=1,
 89                gap_closing_cost_cutoff=False,
 90                merging_cost_cutoff=self.merging_cost,
 91                merging_dist_metric_coefs=(1.0, 0.0, 0.0, -1.0, 0.0),
 92                splitting_cost_cutoff=self.splitting_cost,
 93                splitting_dist_metric_coefs=(1.0, 0.0, 0.0, 0.0, -1.0),
 94            )
 95        
 96        track_df, split_df, merge_df = ol.predict_overlap_dataframe(labels)
 97        ## handle eventual missing frames
 98        track_df = track_df.reset_index()
 99        track_df["frame"] += np.searchsorted(sorted(ind), track_df["frame"], side='right')
100
101        track_df = track_df.reset_index()
102        return track_df, split_df, merge_df
103
104    def track_overlaps(self, labels):
105        """ Track all movie with laptrack overlap method """
106        ut.napari_info("Starting tracking with laptrack Overlap...")
107        return self.perform_track( labels )
108
109
110    def inspect_oneframe(self, graph, trackdf):
111        for track in np.unique(trackdf["track_id"]):
112            tr = trackdf[trackdf["track_id"] == track]
113            ## track is only on one frame, suspect
114            if len(np.unique(tr["frame"])) == 1:
115                # trackid + 1 as trackid starts as 0
116                pos = (tr.iloc[0]["frame"], int(tr.iloc[0]["centroid-0"]), int(tr.iloc[0]["centroid-1"]))
117                self.epicure.inspecting.add_event( pos, track+1, "tracking" )
118                if self.track.suggesting:
119                    if track in graph.keys():
120                        sisters = []
121                        refval = graph[track][0]
122                        for key, val in graph.items():
123                            if val[0] == refval:
124                                sisters.append( key )
125                        if len(sisters) == 2:
126                            for sis in sisters:
127                                self.epicure.add_suggestion( sis+1, refval+1 )
LaptrackOverlaps(track, epic)
20    def __init__(self, track, epic):
21        self.splitting_cost = 1
22        self.cost_cutoff = 0.9
23        self.merging_cost = 1
24        self.track = track
25        self.epicure = epic
26        self.inspecting = False
27        self.suggesting = False
28        ## to handle difference in laptrack versions
29        self.version_over = Version(laptrack.__version__) >= Version("0.17.0")
splitting_cost
cost_cutoff
merging_cost
track
epicure
inspecting
suggesting
version_over
def twoframes_track(self, img_labels, labels):
32    def twoframes_track(self, img_labels, labels):
33        """ Do track between two frames, only track label """
34        #start_time = time.time()
35        track_df, split_df, merge_df = self.perform_track( img_labels )
36        #show_info("Performed in "+"{:.3f}".format((time.time()-start_time)/60)+" min")
37        
38        track_ids = [None]*len(labels)
39        ## look for track id associated with label
40        for i, row in track_df.iterrows():
41            frame = int(row["frame"])
42            if frame == 1:
43                tid = int(row["track_id"])
44                curlabel = int(row["label"])
45                ind = labels.index(curlabel)
46                track_ids[ind] = tid
47
48        tracklabels = [None]*len(labels)
49        ## look for cell label associated with track_id in the first frame, if any
50        for i, row in track_df.iterrows():
51            frame = int(row["frame"])
52            tid = int(row["track_id"])
53            if (tid in track_ids) and (frame==0):
54                ind = track_ids.index(tid)
55                label = int(row["label"])
56                tracklabels[ind] = label 
57        #show_info("Finished in "+"{:.3f}".format((time.time()-start_time)/60)+" min")
58        return tracklabels

Do track between two frames, only track label

def perform_track(self, labels):
 61    def perform_track(self, labels):
 62        """ Do tracking with laptrack module """
 63
 64        ## handling eventual missing (empty) frame:
 65        ind = []
 66        for i, lab in enumerate(labels):
 67            if len(np.unique(lab)) == 1:
 68                ind.append(i)
 69        labels = [ lab for i, lab in enumerate(labels) if i not in ind]
 70
 71        if self.version_over:
 72            ol = OverLapTrack(
 73                cutoff=self.cost_cutoff,
 74                metric_coefs=(1.0, 0.0, -1.0, 0.0, 0.0),
 75                #gap_closing_metric_coefs=(1.0, -1.0, 0.0, 0.0, 0.0),
 76                #gap_closing_max_frame_count=1,
 77                gap_closing_cutoff=False,
 78                merging_cutoff=self.merging_cost,
 79                merging_metric_coefs=(1.0, 0.0, 0.0, -1.0, 0.0),
 80                splitting_cutoff=self.splitting_cost,
 81                splitting_metric_coefs=(1.0, 0.0, 0.0, 0.0, -1.0),
 82            )
 83        else:
 84            ol = OverLapTrack(
 85                track_cost_cutoff=self.cost_cutoff,
 86                track_dist_metric_coefs=(1.0, 0.0, -1.0, 0.0, 0.0),
 87                #gap_closing_dist_metric_coefs=(1.0, -1.0, 0.0, 0.0, 0.0),
 88                #gap_closing_max_frame_count=1,
 89                gap_closing_cost_cutoff=False,
 90                merging_cost_cutoff=self.merging_cost,
 91                merging_dist_metric_coefs=(1.0, 0.0, 0.0, -1.0, 0.0),
 92                splitting_cost_cutoff=self.splitting_cost,
 93                splitting_dist_metric_coefs=(1.0, 0.0, 0.0, 0.0, -1.0),
 94            )
 95        
 96        track_df, split_df, merge_df = ol.predict_overlap_dataframe(labels)
 97        ## handle eventual missing frames
 98        track_df = track_df.reset_index()
 99        track_df["frame"] += np.searchsorted(sorted(ind), track_df["frame"], side='right')
100
101        track_df = track_df.reset_index()
102        return track_df, split_df, merge_df

Do tracking with laptrack module

def track_overlaps(self, labels):
104    def track_overlaps(self, labels):
105        """ Track all movie with laptrack overlap method """
106        ut.napari_info("Starting tracking with laptrack Overlap...")
107        return self.perform_track( labels )

Track all movie with laptrack overlap method

def inspect_oneframe(self, graph, trackdf):
110    def inspect_oneframe(self, graph, trackdf):
111        for track in np.unique(trackdf["track_id"]):
112            tr = trackdf[trackdf["track_id"] == track]
113            ## track is only on one frame, suspect
114            if len(np.unique(tr["frame"])) == 1:
115                # trackid + 1 as trackid starts as 0
116                pos = (tr.iloc[0]["frame"], int(tr.iloc[0]["centroid-0"]), int(tr.iloc[0]["centroid-1"]))
117                self.epicure.inspecting.add_event( pos, track+1, "tracking" )
118                if self.track.suggesting:
119                    if track in graph.keys():
120                        sisters = []
121                        refval = graph[track][0]
122                        for key, val in graph.items():
123                            if val[0] == refval:
124                                sisters.append( key )
125                        if len(sisters) == 2:
126                            for sis in sisters:
127                                self.epicure.add_suggestion( sis+1, refval+1 )