From f20daebe8383ab4a3a58d8d1b53541d35f380c4e Mon Sep 17 00:00:00 2001 From: JESUSROYETH <42451234+JESUSROYETH@users.noreply.github.com> Date: Thu, 3 Jul 2025 17:29:04 -0400 Subject: [PATCH 1/3] fix(line_zone): index crossing state by (tracker_id, class_id) --- supervision/detection/line_zone.py | 8 ++--- test/detection/test_line_counter.py | 51 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/supervision/detection/line_zone.py b/supervision/detection/line_zone.py index b63660bc4..3b6b06257 100644 --- a/supervision/detection/line_zone.py +++ b/supervision/detection/line_zone.py @@ -99,7 +99,7 @@ def __init__( self.vector = Vector(start=start, end=end) self.limits = self._calculate_region_of_interest_limits(vector=self.vector) self.crossing_history_length = max(2, minimum_crossing_threshold + 1) - self.crossing_state_history: Dict[int, Deque[bool]] = defaultdict( + self.crossing_state_history: Dict[Tuple[int, int], Deque[bool]] = defaultdict( lambda: deque(maxlen=self.crossing_history_length) ) self._in_count_per_class: Counter = Counter() @@ -176,16 +176,12 @@ def trigger(self, detections: Detections) -> Tuple[np.ndarray, np.ndarray]: continue tracker_state: bool = has_any_left_trigger[i] - crossing_history = self.crossing_state_history[tracker_id] + crossing_history = self.crossing_state_history[(tracker_id, class_id)] crossing_history.append(tracker_state) if len(crossing_history) < self.crossing_history_length: continue - # TODO: Account for incorrect class_id. - # Most likely this would involve indexing self.crossing_state_history - # with (tracker_id, class_id). - oldest_state = crossing_history[0] if crossing_history.count(oldest_state) > 1: continue diff --git a/test/detection/test_line_counter.py b/test/detection/test_line_counter.py index 0119cf86e..ff1a73d02 100644 --- a/test/detection/test_line_counter.py +++ b/test/detection/test_line_counter.py @@ -776,3 +776,54 @@ def test_line_zone_long_horizon_disappearing_detections( assert crossed_out_list == expected_crossed_out assert count_in_list == expected_count_in assert count_out_list == expected_count_out + + +def test_line_zone_tracker_id_reuse_with_different_classes() -> None: + line_zone = LineZone(start=Point(0, 0), end=Point(10, 0)) + + # First object with class 0 crosses the line + detections = mock_detections( + xyxy=[[4, 4, 6, 6]], + tracker_id=[0], + class_id=[0], + ) + line_zone.trigger(detections) + + detections = mock_detections( + xyxy=[[4, -6, 6, -4]], + tracker_id=[0], + class_id=[0], + ) + line_zone.trigger(detections) + + detections = mock_detections( + xyxy=[[4, 4, 6, 6]], + tracker_id=[0], + class_id=[0], + ) + line_zone.trigger(detections) + + # Second object reuses tracker id with a different class + detections = mock_detections( + xyxy=[[4, 4, 6, 6]], + tracker_id=[0], + class_id=[1], + ) + line_zone.trigger(detections) + + detections = mock_detections( + xyxy=[[4, -6, 6, -4]], + tracker_id=[0], + class_id=[1], + ) + line_zone.trigger(detections) + + detections = mock_detections( + xyxy=[[4, 4, 6, 6]], + tracker_id=[0], + class_id=[1], + ) + line_zone.trigger(detections) + + assert line_zone.in_count_per_class == {0: 1, 1: 1} + assert line_zone.out_count_per_class == {0: 1, 1: 1} \ No newline at end of file From a0a720173bb4f75f18d02bcebd77ac71d9523cb2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 21:42:21 +0000 Subject: [PATCH 2/3] =?UTF-8?q?fix(pre=5Fcommit):=20=F0=9F=8E=A8=20auto=20?= =?UTF-8?q?format=20pre-commit=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/detection/test_line_counter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/detection/test_line_counter.py b/test/detection/test_line_counter.py index ff1a73d02..fcd894309 100644 --- a/test/detection/test_line_counter.py +++ b/test/detection/test_line_counter.py @@ -826,4 +826,4 @@ def test_line_zone_tracker_id_reuse_with_different_classes() -> None: line_zone.trigger(detections) assert line_zone.in_count_per_class == {0: 1, 1: 1} - assert line_zone.out_count_per_class == {0: 1, 1: 1} \ No newline at end of file + assert line_zone.out_count_per_class == {0: 1, 1: 1} From 4bfeae49eafc16b2d96f1faf0dc51c7813858ade Mon Sep 17 00:00:00 2001 From: JESUSROYETH <42451234+JESUSROYETH@users.noreply.github.com> Date: Thu, 3 Jul 2025 18:11:55 -0400 Subject: [PATCH 3/3] style(utils): satisfy Ruff RUF005 in image.py --- supervision/utils/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supervision/utils/image.py b/supervision/utils/image.py index 0bd2dbaac..37025656b 100644 --- a/supervision/utils/image.py +++ b/supervision/utils/image.py @@ -785,4 +785,4 @@ def _merge_tiles_elements( def _generate_color_image( shape: Tuple[int, int], color: Tuple[int, int, int] ) -> np.ndarray: - return np.ones(shape[::-1] + (3,), dtype=np.uint8) * color + return np.ones((*shape[::-1], 3), dtype=np.uint8) * color