From 85789097e6ef69ae4251ee6715a97ba69068a371 Mon Sep 17 00:00:00 2001 From: a2misic Date: Fri, 29 Nov 2024 17:22:53 -0500 Subject: [PATCH 1/4] implemented label in cluster estimation --- .../cluster_estimation/cluster_estimation.py | 6 +- modules/object_in_world.py | 10 ++- tests/unit/test_decision.py | 14 ++-- tests/unit/test_landing_pad_tracking.py | 72 +++++++++---------- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/modules/cluster_estimation/cluster_estimation.py b/modules/cluster_estimation/cluster_estimation.py index ae7ff0b3..7e34edc4 100644 --- a/modules/cluster_estimation/cluster_estimation.py +++ b/modules/cluster_estimation/cluster_estimation.py @@ -199,17 +199,17 @@ def run( # Remove clusters with covariances too large model_output = self.__filter_by_covariances(model_output) + label = 0 # Create output list of remaining valid clusters detections_in_world = [] for cluster in model_output: result, landing_pad = object_in_world.ObjectInWorld.create( - cluster[0][0], - cluster[0][1], - cluster[2], + cluster[0][0], cluster[0][1], cluster[2], label ) if result: detections_in_world.append(landing_pad) + label += 1 else: self.__logger.warning("Failed to create ObjectInWorld object") diff --git a/modules/object_in_world.py b/modules/object_in_world.py index 83922253..759e47c2 100644 --- a/modules/object_in_world.py +++ b/modules/object_in_world.py @@ -12,7 +12,7 @@ class ObjectInWorld: @classmethod def create( - cls, location_x: float, location_y: float, spherical_variance: float + cls, location_x: float, location_y: float, spherical_variance: float, label: int ) -> "tuple[bool, ObjectInWorld | None]": """ location_x, location_y: Location of the object. @@ -21,7 +21,9 @@ def create( if spherical_variance < 0.0: return False, None - return True, ObjectInWorld(cls.__create_key, location_x, location_y, spherical_variance) + return True, ObjectInWorld( + cls.__create_key, location_x, location_y, spherical_variance, label + ) def __init__( self, @@ -29,6 +31,7 @@ def __init__( location_x: float, location_y: float, spherical_variance: float, + label: int, ) -> None: """ Private constructor, use create() method. @@ -38,12 +41,13 @@ def __init__( self.location_x = location_x self.location_y = location_y self.spherical_variance = spherical_variance + self.label = label def __str__(self) -> str: """ To string. """ - return f"{self.__class__}, location_x: {self.location_x}, location_y: {self.location_y}, spherical_variance: {self.spherical_variance}" + return f"{self.__class__}, location_x: {self.location_x}, location_y: {self.location_y}, spherical_variance: {self.spherical_variance}, label: {self.label}" def __repr__(self) -> str: """ diff --git a/tests/unit/test_decision.py b/tests/unit/test_decision.py index 3b3cf68f..ce9192ea 100644 --- a/tests/unit/test_decision.py +++ b/tests/unit/test_decision.py @@ -43,7 +43,9 @@ def best_pad_within_tolerance() -> object_in_world.ObjectInWorld: # type: ignor location_x = BEST_PAD_LOCATION_X location_y = BEST_PAD_LOCATION_Y spherical_variance = 1.0 - result, pad = object_in_world.ObjectInWorld.create(location_x, location_y, spherical_variance) + result, pad = object_in_world.ObjectInWorld.create( + location_x, location_y, spherical_variance, 0 + ) assert result assert pad is not None @@ -58,7 +60,9 @@ def best_pad_outside_tolerance() -> object_in_world.ObjectInWorld: # type: igno location_x = 100.0 location_y = 200.0 spherical_variance = 5.0 # variance outside tolerance - result, pad = object_in_world.ObjectInWorld.create(location_x, location_y, spherical_variance) + result, pad = object_in_world.ObjectInWorld.create( + location_x, location_y, spherical_variance, 0 + ) assert result assert pad is not None @@ -70,15 +74,15 @@ def pads() -> "list[object_in_world.ObjectInWorld]": # type: ignore """ Create a list of ObjectInWorld instances for the landing pads. """ - result, pad_1 = object_in_world.ObjectInWorld.create(30.0, 40.0, 2.0) + result, pad_1 = object_in_world.ObjectInWorld.create(30.0, 40.0, 2.0, 0) assert result assert pad_1 is not None - result, pad_2 = object_in_world.ObjectInWorld.create(50.0, 60.0, 3.0) + result, pad_2 = object_in_world.ObjectInWorld.create(50.0, 60.0, 3.0, 0) assert result assert pad_2 is not None - result, pad_3 = object_in_world.ObjectInWorld.create(70.0, 80.0, 4.0) + result, pad_3 = object_in_world.ObjectInWorld.create(70.0, 80.0, 4.0, 0) assert result assert pad_3 is not None diff --git a/tests/unit/test_landing_pad_tracking.py b/tests/unit/test_landing_pad_tracking.py index fd6fce60..5faa1f8f 100644 --- a/tests/unit/test_landing_pad_tracking.py +++ b/tests/unit/test_landing_pad_tracking.py @@ -30,23 +30,23 @@ def detections_1() -> "list[object_in_world.ObjectInWorld]": # type: ignore """ Sample instances of ObjectInWorld for testing. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 8) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 8, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(2, 2, 4) + result, obj_2 = object_in_world.ObjectInWorld.create(2, 2, 4, 0) assert result assert obj_2 is not None - result, obj_3 = object_in_world.ObjectInWorld.create(-2, -2, 2) + result, obj_3 = object_in_world.ObjectInWorld.create(-2, -2, 2, 0) assert result assert obj_3 is not None - result, obj_4 = object_in_world.ObjectInWorld.create(3, 3, 10) + result, obj_4 = object_in_world.ObjectInWorld.create(3, 3, 10, 0) assert result assert obj_4 is not None - result, obj_5 = object_in_world.ObjectInWorld.create(-3, -3, 6) + result, obj_5 = object_in_world.ObjectInWorld.create(-3, -3, 6, 0) assert result assert obj_5 is not None @@ -59,23 +59,23 @@ def detections_2() -> "list[object_in_world.ObjectInWorld]": # type: ignore """ Sample instances of ObjectInWorld for testing. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0.5, 0.5, 1) + result, obj_1 = object_in_world.ObjectInWorld.create(0.5, 0.5, 1, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(1.5, 1.5, 3) + result, obj_2 = object_in_world.ObjectInWorld.create(1.5, 1.5, 3, 0) assert result assert obj_2 is not None - result, obj_3 = object_in_world.ObjectInWorld.create(4, 4, 7) + result, obj_3 = object_in_world.ObjectInWorld.create(4, 4, 7, 0) assert result assert obj_3 is not None - result, obj_4 = object_in_world.ObjectInWorld.create(-4, -4, 5) + result, obj_4 = object_in_world.ObjectInWorld.create(-4, -4, 5, 0) assert result assert obj_4 is not None - result, obj_5 = object_in_world.ObjectInWorld.create(5, 5, 9) + result, obj_5 = object_in_world.ObjectInWorld.create(5, 5, 9, 0) assert result assert obj_5 is not None @@ -88,23 +88,23 @@ def detections_3() -> "list[object_in_world.ObjectInWorld]": # type: ignore """ Sample instances of ObjectInWorld for testing. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 8) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 8, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(0.5, 0.5, 4) + result, obj_2 = object_in_world.ObjectInWorld.create(0.5, 0.5, 4, 0) assert result assert obj_2 is not None - result, obj_3 = object_in_world.ObjectInWorld.create(-2, -2, 2) + result, obj_3 = object_in_world.ObjectInWorld.create(-2, -2, 2, 0) assert result assert obj_3 is not None - result, obj_4 = object_in_world.ObjectInWorld.create(3, 3, 10) + result, obj_4 = object_in_world.ObjectInWorld.create(3, 3, 10, 0) assert result assert obj_4 is not None - result, obj_5 = object_in_world.ObjectInWorld.create(-3, -3, 6) + result, obj_5 = object_in_world.ObjectInWorld.create(-3, -3, 6, 0) assert result assert obj_5 is not None @@ -123,11 +123,11 @@ def test_is_similar_positive_equal_to_threshold(self) -> None: Test case where the second landing pad has positive coordinates and the distance between them is equal to the distance threshold. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(1, 1, 0) + result, obj_2 = object_in_world.ObjectInWorld.create(1, 1, 0, 0) assert result assert obj_2 is not None @@ -145,11 +145,11 @@ def test_is_similar_negative_equal_to_threshold(self) -> None: Test case where the second landing pad has negative coordinates and the distance between them is equal to the distance threshold. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(-1, -1, 0) + result, obj_2 = object_in_world.ObjectInWorld.create(-1, -1, 0, 0) assert result assert obj_2 is not None @@ -168,11 +168,11 @@ def test_is_similar_positive_less_than_threshold(self) -> None: Test case where the second landing pad has positive coordinates and the distance between them is less than the distance threshold. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(0.5, 0.5, 0) + result, obj_2 = object_in_world.ObjectInWorld.create(0.5, 0.5, 0, 0) assert result assert obj_2 is not None @@ -191,11 +191,11 @@ def test_is_similar_negative_less_than_threshold(self) -> None: Test case where the second landing pad has negative coordinates and the distance between them is less than the distance threshold. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(-0.5, -0.5, 0) + result, obj_2 = object_in_world.ObjectInWorld.create(-0.5, -0.5, 0, 0) assert result assert obj_2 is not None @@ -214,11 +214,11 @@ def test_is_similar_positive_more_than_threshold(self) -> None: Test case where the second landing pad has positive coordinates and the distance between them is more than the distance threshold. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(2, 2, 0) + result, obj_2 = object_in_world.ObjectInWorld.create(2, 2, 0, 0) assert result assert obj_2 is not None @@ -237,11 +237,11 @@ def test_is_similar_negative_more_than_threshold(self) -> None: Test case where the second landing pad has negative coordinates and the distance between them is more than the distance threshold. """ - result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0) + result, obj_1 = object_in_world.ObjectInWorld.create(0, 0, 0, 0) assert result assert obj_1 is not None - result, obj_2 = object_in_world.ObjectInWorld.create(-2, -2, 0) + result, obj_2 = object_in_world.ObjectInWorld.create(-2, -2, 0, 0) assert result assert obj_2 is not None @@ -269,7 +269,7 @@ def test_mark_false_positive_no_similar( """ Test if marking false positive adds detection to list of false positives. """ - _, false_positive = object_in_world.ObjectInWorld.create(20, 20, 20) + _, false_positive = object_in_world.ObjectInWorld.create(20, 20, 20, 0) assert false_positive is not None tracker._LandingPadTracking__unconfirmed_positives = detections_1 # type: ignore @@ -296,7 +296,7 @@ def test_mark_false_positive_with_similar( Test if marking false positive adds detection to list of false positives and removes. similar landing pads """ - _, false_positive = object_in_world.ObjectInWorld.create(1, 1, 1) + _, false_positive = object_in_world.ObjectInWorld.create(1, 1, 1, 0) assert false_positive is not None tracker._LandingPadTracking__unconfirmed_positives = detections_2 # type: ignore @@ -316,10 +316,10 @@ def test_mark_multiple_false_positive( """ Test if marking false positive adds detection to list of false positives. """ - _, false_positive_1 = object_in_world.ObjectInWorld.create(0, 0, 1) + _, false_positive_1 = object_in_world.ObjectInWorld.create(0, 0, 1, 0) assert false_positive_1 is not None - _, false_positive_2 = object_in_world.ObjectInWorld.create(2, 2, 1) + _, false_positive_2 = object_in_world.ObjectInWorld.create(2, 2, 1, 0) assert false_positive_2 is not None tracker._LandingPadTracking__unconfirmed_positives = detections_1 # type: ignore @@ -344,7 +344,7 @@ def test_mark_confirmed_positive( """ Test if marking confirmed positive adds detection to list of confirmed positives. """ - _, confirmed_positive = object_in_world.ObjectInWorld.create(1, 1, 1) + _, confirmed_positive = object_in_world.ObjectInWorld.create(1, 1, 1, 0) assert confirmed_positive is not None expected = [confirmed_positive] @@ -359,10 +359,10 @@ def test_mark_multiple_confirmed_positives( """ Test if marking confirmed positive adds detection to list of confirmed positives. """ - _, confirmed_positive_1 = object_in_world.ObjectInWorld.create(1, 1, 1) + _, confirmed_positive_1 = object_in_world.ObjectInWorld.create(1, 1, 1, 0) assert confirmed_positive_1 is not None - _, confirmed_positive_2 = object_in_world.ObjectInWorld.create(2, 2, 1) + _, confirmed_positive_2 = object_in_world.ObjectInWorld.create(2, 2, 1, 0) assert confirmed_positive_2 is not None expected = [confirmed_positive_1, confirmed_positive_2] @@ -478,7 +478,7 @@ def test_run_with_confirmed_positive( Test run when there is a confirmed positive. """ # Setup - result, confirmed_positive = object_in_world.ObjectInWorld.create(1, 1, 1) + result, confirmed_positive = object_in_world.ObjectInWorld.create(1, 1, 1, 0) assert result assert confirmed_positive is not None @@ -501,7 +501,7 @@ def test_run_with_false_positive( Test to see if run function doesn't add landing pads that are similar to false positives. """ # Setup - result, false_positive = object_in_world.ObjectInWorld.create(1, 1, 1) + result, false_positive = object_in_world.ObjectInWorld.create(1, 1, 1, 0) assert result assert false_positive is not None From b5bcd18a6ef9d1deda383e32337da6a140c4fe68 Mon Sep 17 00:00:00 2001 From: a2misic Date: Fri, 29 Nov 2024 19:22:55 -0500 Subject: [PATCH 2/4] implemented cluster estimation label by detection label --- .../cluster_estimation/cluster_estimation.py | 128 +++++++++++++++--- 1 file changed, 112 insertions(+), 16 deletions(-) diff --git a/modules/cluster_estimation/cluster_estimation.py b/modules/cluster_estimation/cluster_estimation.py index 7e34edc4..6783489c 100644 --- a/modules/cluster_estimation/cluster_estimation.py +++ b/modules/cluster_estimation/cluster_estimation.py @@ -34,15 +34,22 @@ class ClusterEstimation: METHODS ------- run() - Take in list of landing pad detections and return list of estimated landing pad locations + Take in list of object detections and return list of estimated object locations if number of detections is sufficient, or if manually forced to run. + cluster_by_label() + Take in list of detections of the same label and return list of estimated object locations + of the same label. + __decide_to_run() Decide when to run cluster estimation model. __sort_by_weights() Sort input model output list by weights in descending order. + __sort_by_labels() + Sort input detection list by labels in descending order. + __convert_detections_to_point() Convert DetectionInWorld input object to a [x,y] position to store. @@ -51,6 +58,7 @@ class ClusterEstimation: __filter_by_covariances() Removes any cluster with covariances much higher than the lowest covariance value. + """ __create_key = object() @@ -131,10 +139,12 @@ def __init__( self.__logger = local_logger def run( - self, detections: "list[detection_in_world.DetectionInWorld]", run_override: bool + self, + detections: "list[detection_in_world.DetectionInWorld]", + run_override: bool, ) -> "tuple[bool, list[object_in_world.ObjectInWorld] | None]": """ - Take in list of landing pad detections and return list of estimated landing pad locations + Take in list of detections and return list of estimated object locations if number of detections is sufficient, or if manually forced to run. PARAMETERS @@ -159,24 +169,92 @@ def run( # Store new input data self.__current_bucket += self.__convert_detections_to_point(detections) + # Decide to run + if not self.__decide_to_run(run_override): + return False, None + + # sort bucket by label in descending order + self.__current_bucket = self.__sort_by_labels(self.__current_bucket) + detections_in_world = [] + + # init search parameters + ptr = 0 + max_label = self.__current_bucket[0][2] + + # itterates through all possible labels + for label in reversed(range(max_label)): + + # creates bucket of labels + bucket_labelled = [] + while ptr < len(self.__current_bucket) and self.__current_bucket[ptr][2] == label: + bucket_labelled += [self.__current_bucket[ptr]] + ptr += 1 + + # skip if no objects have label=label + if len(bucket_labelled) == 0: + continue + + check, labelled_detections_in_world = self.cluster_by_label( + bucket_labelled, run_override, label + ) + + # checks if cluster_by_label ran succssfully + if not check: + self.__logger(f"did not add objects of label={label} to total object detections") + continue + + detections_in_world += labelled_detections_in_world + + return True, detections_in_world + + def cluster_by_label( + self, + points: "list[tuple[float, float, int]]", + run_override: bool, + label: int, + ) -> "tuple[bool, list[object_in_world.ObjectInWorld] | None]": + """ + Take in list of detections of the same label and return list of estimated object locations + of the same label. + + PARAMETERS + ---------- + points: list[tuple[float, float, int]] + List containing tuple objects which holds real-world positioning data to run + clustering on and their labels + + run_override: bool + Forces ClusterEstimation to predict if data is available, regardless of any other + requirements. + + RETURNS + ------- + model_ran: bool + True if ClusterEstimation object successfully ran its estimation model, False otherwise. + + objects_in_world: list[ObjectInWorld] or None. + List containing ObjectInWorld objects, containing position and covariance value. + None if conditions not met and model not ran or model failed to converge. + """ + # Decide to run if not self.__decide_to_run(run_override): return False, None # Fit points and get cluster data - self.__vgmm = self.__vgmm.fit(self.__all_points) # type: ignore + __vgmm_label = self.__vgmm.fit(points) # type: ignore # Check convergence - if not self.__vgmm.converged_: - self.__logger.warning("Model failed to converge") + if not __vgmm_label.converged_: + self.__logger.warning(f"Model for label={label} failed to converge") return False, None # Get predictions from cluster model model_output: "list[tuple[np.ndarray, float, float]]" = list( zip( - self.__vgmm.means_, # type: ignore - self.__vgmm.weights_, # type: ignore - self.__vgmm.covariances_, # type: ignore + __vgmm_label.means_, # type: ignore + __vgmm_label.weights_, # type: ignore + __vgmm_label.covariances_, # type: ignore ) ) @@ -199,7 +277,6 @@ def run( # Remove clusters with covariances too large model_output = self.__filter_by_covariances(model_output) - label = 0 # Create output list of remaining valid clusters detections_in_world = [] for cluster in model_output: @@ -209,7 +286,6 @@ def run( if result: detections_in_world.append(landing_pad) - label += 1 else: self.__logger.warning("Failed to create ObjectInWorld object") @@ -274,12 +350,32 @@ def __sort_by_weights( """ return sorted(model_output, key=lambda x: x[1], reverse=True) + @staticmethod + def __sort_by_labels( + points: "list[tuple[float, float, int]]", + ) -> "list[tuple[float, float, int]]": + """ + Sort input detection list by labels in descending order. + + PARAMETERS + ---------- + detections: list[tuple[float, float, int]] + List containing detections, with each element having the format + [x_position, y_position, label]. + + RETURNS + ------- + list[tuple[np.ndarray, float, float]] + List containing detection points sorted in descending order by label + """ + return sorted(points, key=lambda x: x.label, reverse=True) + @staticmethod def __convert_detections_to_point( detections: "list[detection_in_world.DetectionInWorld]", - ) -> "list[tuple[float, float]]": + ) -> "list[tuple[float, float, int]]": """ - Convert DetectionInWorld input object to a list of points- (x,y) positions, to store. + Convert DetectionInWorld input object to a list of points- (x,y) positions with label, to store. PARAMETERS ---------- @@ -289,8 +385,8 @@ def __convert_detections_to_point( RETURNS ------- - points: list[tuple[float, float]] - List of points (x,y). + points: list[tuple[float, float, int]] + List of points (x,y) and their label ------- """ points = [] @@ -302,7 +398,7 @@ def __convert_detections_to_point( # Convert DetectionInWorld objects for detection in detections: # `centre` attribute holds positioning data - points.append(tuple([detection.centre[0], detection.centre[1]])) + points.append(tuple([detection.centre[0], detection.centre[1], detection.label])) return points From f68c8eae47cc83468b49c613ffa5be5349000c5b Mon Sep 17 00:00:00 2001 From: a2misic Date: Wed, 18 Dec 2024 21:20:23 -0500 Subject: [PATCH 3/4] fixed implementation --- modules/cluster_estimation/cluster_estimation.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/cluster_estimation/cluster_estimation.py b/modules/cluster_estimation/cluster_estimation.py index 6783489c..6943b591 100644 --- a/modules/cluster_estimation/cluster_estimation.py +++ b/modules/cluster_estimation/cluster_estimation.py @@ -58,7 +58,6 @@ class ClusterEstimation: __filter_by_covariances() Removes any cluster with covariances much higher than the lowest covariance value. - """ __create_key = object() @@ -179,12 +178,13 @@ def run( # init search parameters ptr = 0 - max_label = self.__current_bucket[0][2] - # itterates through all possible labels - for label in reversed(range(max_label)): + # itterates through all points + while ptr <= len(self.__current_bucket): + # reference label + label = self.__current_bucket[ptr][2] - # creates bucket of labels + # creates bucket of points with the same label bucket_labelled = [] while ptr < len(self.__current_bucket) and self.__current_bucket[ptr][2] == label: bucket_labelled += [self.__current_bucket[ptr]] @@ -200,7 +200,9 @@ def run( # checks if cluster_by_label ran succssfully if not check: - self.__logger(f"did not add objects of label={label} to total object detections") + self.__logger.warning( + f"did not add objects of label={label} to total object detections" + ) continue detections_in_world += labelled_detections_in_world From 3134b2a4271a070646a0135a68e6f480cb0c0836 Mon Sep 17 00:00:00 2001 From: a2misic Date: Mon, 6 Jan 2025 21:32:26 -0500 Subject: [PATCH 4/4] implemented fixes --- modules/cluster_estimation/cluster_estimation.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/cluster_estimation/cluster_estimation.py b/modules/cluster_estimation/cluster_estimation.py index 6943b591..f8985e06 100644 --- a/modules/cluster_estimation/cluster_estimation.py +++ b/modules/cluster_estimation/cluster_estimation.py @@ -173,7 +173,7 @@ def run( return False, None # sort bucket by label in descending order - self.__current_bucket = self.__sort_by_labels(self.__current_bucket) + self.__all_points = self.__sort_by_labels(self.__current_bucket) detections_in_world = [] # init search parameters @@ -184,22 +184,22 @@ def run( # reference label label = self.__current_bucket[ptr][2] - # creates bucket of points with the same label + # creates bucket of points with the same label since bucket is sorted by label bucket_labelled = [] - while ptr < len(self.__current_bucket) and self.__current_bucket[ptr][2] == label: - bucket_labelled += [self.__current_bucket[ptr]] + while ptr < len(self.__current_bucket) and self.__all_points[ptr][2] == label: + bucket_labelled.append([self.__all_points[ptr]]) ptr += 1 # skip if no objects have label=label if len(bucket_labelled) == 0: continue - check, labelled_detections_in_world = self.cluster_by_label( + result, labelled_detections_in_world = self.cluster_by_label( bucket_labelled, run_override, label ) # checks if cluster_by_label ran succssfully - if not check: + if not result: self.__logger.warning( f"did not add objects of label={label} to total object detections" )