Fix external track ids (#1364)
* fix exteranl track ids getting assigned too early * Fixed docstring to correct minimum_matching_threshold explaination * Change overlap value for duplicate tracks to be 0.05 * Add test to ensure ByteTracker handles short-lived tracks without consuming external IDs --------- Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
This commit is contained in:
1 parent
6576a846d9
commit
b5ccf6882d
3 files changed
+30
-6
No files matched your search
@@ -31,8 +31,8 @@ class ByteTrack:
|
||||
reducing the likelihood of track fragmentation or disappearance caused
|
||||
by brief detection gaps.
|
||||
minimum_matching_threshold: Threshold for matching tracks with detections.
|
||||
Increasing minimum_matching_threshold improves accuracy but risks fragmentation.
|
||||
Decreasing it improves completeness but risks false positives and drift.
|
||||
Decreasing minimum_matching_threshold improves accuracy but risks fragmentation.
|
||||
Increasing it improves completeness but risks false positives and drift.
|
||||
frame_rate: The frame rate of the video.
|
||||
minimum_consecutive_frames: Number of consecutive frames that an object must
|
||||
be tracked before it is considered a 'valid' track.
|
||||
@@ -371,7 +371,7 @@ def remove_duplicate_tracks(
|
||||
tracks_a: list[STrack], tracks_b: list[STrack]
|
||||
) -> tuple[list[STrack], list[STrack]]:
|
||||
pairwise_distance = matching.iou_distance(tracks_a, tracks_b)
|
||||
matching_pairs = np.where(pairwise_distance < 0.15)
|
||||
matching_pairs = np.where(pairwise_distance < 0.05)
|
||||
|
||||
duplicates_a, duplicates_b = set(), set()
|
||||
for track_index_a, track_index_b in zip(*matching_pairs):
|
||||
|
||||
@@ -91,9 +91,8 @@ class STrack:
|
||||
self.state = TrackState.Tracked
|
||||
if frame_id == 1:
|
||||
self.is_activated = True
|
||||
|
||||
if self.minimum_consecutive_frames == 1:
|
||||
self.external_track_id = self.external_id_counter.new_id()
|
||||
if self.minimum_consecutive_frames == 1:
|
||||
self.external_track_id = self.external_id_counter.new_id()
|
||||
|
||||
self.frame_id = frame_id
|
||||
self.start_frame = frame_id
|
||||
|
||||
@@ -36,3 +36,28 @@ def test_byte_tracker(
|
||||
byte_tracker = sv.ByteTrack()
|
||||
tracked_detections = [byte_tracker.update_with_detections(d) for d in detections]
|
||||
assert tracked_detections[-1] == expected_results
|
||||
|
||||
|
||||
def test_byte_tracker_does_not_skip_external_ids_for_short_lived_tracks() -> None:
|
||||
def detections_from_boxes(boxes: list[list[float]]) -> sv.Detections:
|
||||
return sv.Detections(
|
||||
xyxy=np.array(boxes, dtype=np.float32),
|
||||
class_id=np.zeros(len(boxes), dtype=int),
|
||||
confidence=np.ones(len(boxes), dtype=np.float32),
|
||||
)
|
||||
|
||||
# A transient false-positive appears and disappears before becoming confirmed.
|
||||
# It should not consume an external tracker id.
|
||||
frames = [
|
||||
detections_from_boxes([[0, 0, 10, 10]]),
|
||||
detections_from_boxes([[0, 0, 10, 10], [100, 100, 110, 110]]),
|
||||
detections_from_boxes([[0, 0, 10, 10]]),
|
||||
detections_from_boxes([[0, 0, 10, 10], [200, 200, 210, 210]]),
|
||||
detections_from_boxes([[0, 0, 10, 10], [200, 200, 210, 210]]),
|
||||
]
|
||||
|
||||
byte_tracker = sv.ByteTrack(minimum_consecutive_frames=1)
|
||||
|
||||
tracked = [byte_tracker.update_with_detections(frame) for frame in frames]
|
||||
assert tracked[-1].tracker_id is not None
|
||||
assert np.array_equal(np.sort(tracked[-1].tracker_id), np.array([1, 2]))
|
||||
Reference in new issue
Block a user