def __assign_detections_to_tracks_munkres(self, detections, frame_id, save=False): # if there are no tracks yet, all detections are new tracks if len(self.tracks) == 0: for det in detections: t = Track() t.add_to_track(det) self.tracks.append(t) return True # find distance from all tracks to all detections and formulate dists matrix dists = np.zeros(shape=(len(self.tracks), len(detections))) for i, track in enumerate(self.tracks): predicted_next_bb = track.get_predicted_next_bb() for j, det in enumerate(detections): dist = util.dist_btwn_bb_centroids(predicted_next_bb, det.bbox) if track.is_singular(): max_dist = const.MAX_PIXELS_DIST_TRACK_START else: max_dist = const.MAX_PIXELS_DIST_TRACK if dist > max_dist: dist = 1e6 # set to arbitrarily high number dists[i, j] = dist # set all tracks as unassigned for t in self.tracks: t.has_match = False # assign all detections to tracks with munkres algorithm assigned_rows, assigned_cols = linear_sum_assignment(dists) for idx, row in enumerate(assigned_rows): col = assigned_cols[idx] # if track is assigned a detection with dist=1e6, discard that assignment if dists[row, col] != 1e6: self.tracks[row].has_match = True detections[col].has_match = True self.tracks[row].add_to_track(detections[col]) self.tracks[row].num_misses = 0 # create new tracks from unassigned detections: for det in detections: if det.has_match is False: t = Track() t.add_to_track(det) self.tracks.append(t) # keep track of how many times a track has gone unassigned for t in self.tracks: if t.has_match is False: t.num_misses += 1 # t.propagate_track(frame_id=frame_id) # cleanup any duplicate tracks that have formed (TODO: how do they form?) self.__delete_duplicate_tracks() # save dead tracks before deletion if save: self.__save_tracks_to_json() # remove dead tracks self.tracks = [t for t in self.tracks if (t.is_dead() is False and t.delete_me is False)]
def _assign_detections_to_tracks(self, detections, frame_id, save=False): # if there are no tracks yet, all detections are new tracks if len(self.tracks) == 0: for det in detections: t = Track() t.add_to_track(det) self.tracks.append(t) return True # assign detections to existing tracks for track in self.tracks: track.has_match = False predicted_next_bb = track.get_predicted_next_bb() for det in detections: # singular tracks search radially if track.is_singular(): iou = util.bb_intersection_over_union( predicted_next_bb, det.bbox) dist = util.dist_btwn_bb_centroids(predicted_next_bb, det.bbox) if dist < const.MAX_PIXELS_DIST_TRACK_START and iou > const.MIN_IOU_TRACK_START: track.add_to_track(det) track.has_match = True track.num_misses = 0 break # established tracks search in predicted location elif track.is_established(): # TODO: get distance, iou to det iou = util.bb_intersection_over_union( predicted_next_bb, det.bbox) dist = util.dist_btwn_bb_centroids(predicted_next_bb, det.bbox) if dist < const.MAX_PIXELS_DIST_TRACK and iou > const.MIN_IOU_TRACK: # print 'pred_n=', predicted_next_bb # print 'iou={},dist={}'.format(iou, dist) sim = self.face_rec_engine.compute_similarity( det.fvec, track.get_latest_fvec()) # print 'sim={}'.format(sim) track.add_to_track(det) track.has_match = True track.num_misses = 0 # TODO: handle case where decision is tough (2 detections very close) break # if no track was assigned, give penalty to track if not track.has_match: # delete singular tracks that didn't get assigned (probably false detection) if track.num_misses > 0: if track.is_singular(): track.delete_me = True # print 'delete singular track' else: # TODO: continue track using predicted state track.propagate_track(frame_id=frame_id) track.num_misses += 1 else: # reset match flag track.has_match = False for i, det in enumerate(detections): # if det hasn't been assigned yet, create new tracks if det.num_matches == 0: # print 'new track created. len(tracks)={}, num_det={}'.format(len(tracks),len(detections)) t = Track() t.add_to_track(det) self.tracks.append(t) elif det.num_matches > 1: # print 'multiple assignment!! (num_matches({})={})'.format(i, det.num_matches) pass # TODO: resolve detections with multiple matches # print 'num_tracks = {}, num dets = {}'.format(len(tracks), len(detections)) # cleanup any duplicate tracks that have formed (TODO: how do they form?) self._delete_duplicate_tracks() # save dead tracks before deletion if save: self._save_tracks_to_json() # remove dead tracks self.tracks = [ t for t in self.tracks if (t.is_dead() is False and t.delete_me is False) ] # for i, track in enumerate(tracks): # print '{}: {}'.format(i, track.get_latest_bb()) return True