diff --git a/demos/multi_camera/src/demo.py b/demos/multi_camera/src/demo.py index 3766130e..ac7d8fb1 100644 --- a/demos/multi_camera/src/demo.py +++ b/demos/multi_camera/src/demo.py @@ -330,10 +330,10 @@ def run(): help="Minimum age of a cluster (or it's objects) to be returned", ) parser.add_argument( - "--filter-by-objects-age", - type=bool, - default=False, - help="Filter cluster by their objects age, instead of the clusters age.", + "--maximum-time-since-last-update", + type=int, + default=1, + help="Filter tracked objects that were not detected recently to not be considered in the distance function of the clusterizer", ) parser.add_argument( "--hit-counter-max", @@ -344,7 +344,7 @@ def run(): parser.add_argument( "--reid-hit-counter-max", type=int, - default=300, + default=500, help="Maximum amount of frames trying to reidentify the object. (Use a value >=0)", ) parser.add_argument( @@ -521,7 +521,6 @@ def conditional_embedding_to_spatial(detection, tracked_object): reid_distance_function=embedding_distance, reid_distance_threshold=args.reid_embedding_correlation_threshold, reid_hit_counter_max=args.reid_hit_counter_max, - pointwise_hit_counter_max=2, ) tracked_objects[path] = [] @@ -562,7 +561,7 @@ def clusterizer_distance(tracker1, tracker2): memory=args.memory, initialization_delay=args.clusterizer_initialization_delay, reid_hit_counter_max=args.reid_hit_counter_max, - use_only_living_trackers=False, + maximum_time_since_last_update=args.maximum_time_since_last_update, ) while True: diff --git a/norfair/multi_camera.py b/norfair/multi_camera.py index e18186ba..5bd26a0a 100644 --- a/norfair/multi_camera.py +++ b/norfair/multi_camera.py @@ -8,7 +8,13 @@ def flatten_list(nested_list): return list(itertools.chain(*nested_list)) -def redefine_distance(distance_function, distance_same_camera): +def redefine_distance( + distance_function, + distance_same_camera, + distance_threshold, + clusters, + maximum_time_since_last_update, +): """ In order to not match trackers of the same camera, we need to make sure that the distance between objects of the same camera is at least: @@ -19,8 +25,32 @@ def redefine_distance(distance_function, distance_same_camera): def new_distance(tracked_object_1, tracked_object_2): if tracked_object_1.camera_name == tracked_object_2.camera_name: return distance_same_camera - else: - return distance_function(tracked_object_1, tracked_object_2) + elif not ( + ( + ( + tracked_object_1.point_hit_counter + >= tracked_object_1.hit_counter_max - maximum_time_since_last_update + ).any() + ) + and ( + ( + tracked_object_2.point_hit_counter + >= tracked_object_2.hit_counter_max - maximum_time_since_last_update + ).any() + ) + ): + for cluster in clusters: + current_ids = { + (tracked_object_1.camera_name, tracked_object_1.id), + (tracked_object_2.camera_name, tracked_object_2.id), + } + if len(current_ids.intersection(set(cluster.tracked_ids))) == 2: + return min( + distance_threshold * 0.99, + distance_function(tracked_object_1, tracked_object_2), + ) + + return distance_function(tracked_object_1, tracked_object_2) return new_distance @@ -135,20 +165,23 @@ def generate_current_clusters( trackers_by_camera, distance_function, distance_threshold, + clusters, join_distance_by="mean", - use_only_living_trackers=False, + maximum_time_since_last_update=1, ): # In case number of camera is variable, I will redefine the distance function distance_same_camera = len(trackers_by_camera) ** 2 * distance_threshold + 1 - distance_function = redefine_distance(distance_function, distance_same_camera) + distance_function = redefine_distance( + distance_function, + distance_same_camera, + distance_threshold, + clusters, + maximum_time_since_last_update, + ) current_clusters = flatten_list(trackers_by_camera) - # use only alive trackers: - if use_only_living_trackers: - current_clusters = [obj for obj in current_clusters if obj.live_points.any()] - if len(current_clusters) > 0: distance_matrix = ( np.zeros((len(current_clusters), len(current_clusters))) @@ -441,7 +474,7 @@ def __init__( memory: int = 3, initialization_delay: int = 4, reid_hit_counter_max: int = 0, - use_only_living_trackers: bool = False, + maximum_time_since_last_update: int = 1, ): """ Associate trackers from different cameras/videos. @@ -479,8 +512,8 @@ def __init__( If doing reid in the tracking, then provide the reid_hit_counter_max so that the MultiCameraClusterizer instance knows for how long to keep storing clusters of tracked objects that have dissapeared. - - use_only_living_trackers: bool. - Filter tracked objects that have no alive points. This can be useful since tracked objects that are not alive might have + - maximum_time_since_last_update: int. + Filter tracked objects that were not detected recently. This can be useful since those tracked objects might have position that will not match well with their position in a different camera. """ if max_votes_grow < 1: @@ -515,7 +548,7 @@ def __init__( self.initialization_delay = initialization_delay + max_votes_grow self.reid_hit_counter_max = reid_hit_counter_max + 1 - self.use_only_living_trackers = use_only_living_trackers + self.maximum_time_since_last_update = maximum_time_since_last_update def update(self, trackers_by_camera): @@ -536,8 +569,9 @@ def update(self, trackers_by_camera): trackers_by_camera, self.distance_function, self.distance_threshold, + self.clusters, self.join_distance_by, - self.use_only_living_trackers, + self.maximum_time_since_last_update, ) self.past_clusters.insert(0, deepcopy(current_clusters))