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)]
Exemple #2
0
    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