Skip to content

fix(line_zone): tracker-id reuse across classes #1868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

JESUSROYETH
Copy link
Contributor

Fix incorrect state tracking when a tracker_id is reused with a different class

LineZone.trigger() stored crossing history by tracker_id only.
If the same ID is later assigned to an object of another class,
the in/out counters mix counts.


Changes

  • line_zone.py – index crossing_state_history with (tracker_id, class_id).
  • New test test_line_zone_tracker_id_reuse_with_different_classes
    proves the fix (counts stay correct for both classes).

Validation

  • pytest passes (new test included).
  • pre-commit run --all-files is clean.

No related issue exists yet.

@SkalskiP
Copy link
Collaborator

SkalskiP commented Jul 4, 2025

Hi @JESUSROYETH, thanks a lot for your interest in supervision. Could you give me a bit more context regarding your comment: "If the same ID is later assigned to an object of another class, the in/out counters mix counts"?

Tracker IDs should be unique across all detections, regardless of class. Not just unique within a single class. So tracker_id should be enough to count objects crossing the line.

@soumik12345 I’m a bit skeptical about relying on class_id in this mechanism. Think about potential future trackers coming to trackers. For example, those based on SAM2. What I’m getting at is that I’m not sure we’ll always be able to guarantee that class_id will be available.

@JESUSROYETH
Copy link
Contributor Author

Hi @SkalskiP 👋

I opened this PR because I stumbled on the TODO in line_zone.py that literally says:

# TODO: Account for incorrect class_id.
#   Most likely this would involve indexing self.crossing_state_history
#   with (tracker_id, class_id).

So the concern was already on the radar, and I thought it would be useful to turn that note into working code plus a regression test.

After reading your feedback I realise we’re approaching the same goal (robust counts) from two slightly different angles:

  • Your stance: a well‑behaved tracker should keep tracker_id globally unique, therefore the bug can’t occur and we prefer to avoid relying on class_id, which future trackers (e.g. SAM‑style segmenters) might not emit.
  • My stance: even with good trackers there are edge‑cases (batch processing, tracker restarts, multi‑tracker set‑ups, ID reuse across datasets) where the numeric ID does get recycled, and the current implementation then merges counts for different objects/classes.

I think the right answer probably lives somewhere in between these views, so let me outline the concrete cases I’ve run into:

1. Tracker reset between clips

ByteTrack, DeepSORT and many others reset their internal counter to 0 when you create a fresh instance. If you process ten short videos back‑to‑back but keep the same LineZone (because you want a global in/out tally), ID 0 will appear ten times for ten different objects – possibly of different classes.

2. Multiple trackers in the same pipeline

It’s not uncommon to run one tracker per class (or per camera) and then merge detections downstream. That immediately breaks the “global uniqueness” assumption.

3. Dataset ground‑truth / evaluation frameworks

Public MOT‑style sets often assign IDs unique within a class, not across the whole frame. Feeding those through Supervision reproduces the mix‑up.

4. Dynamic class switching

A single track can flip from person → bicycle after a long occlusion. Keying by (id, class) cleanly splits the two phases.


A middle‑ground proposal

  • Graceful fallback: use (tracker_id, class_id or -1) as the key. If a future tracker omits class_id, everything works exactly as today.
  • Optional behaviour flag: a kw‑arg like use_class_in_history: bool = True keeps full backward compatibility and lets strict‑ID users turn it off.
  • Documented reset hook: add a small note in the docs (or a LineZone.reset()) explaining that if users restart their tracker they should also reset the zone if they want pristine IDs.

I’m happy to implement whichever flavour you prefer, add comments, or tweak the test so it’s skipped when class_id is missing.

Thanks again for the thoughtful review – let me know what you think ..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants