ngperception/tracking: SORT baseline, evaluator and a dataset-free harness - #2
Open
egeboy35 wants to merge 1 commit into
Open
ngperception/tracking: SORT baseline, evaluator and a dataset-free harness#2egeboy35 wants to merge 1 commit into
egeboy35 wants to merge 1 commit into
Conversation
The README's task table listed Tracking (MOT) as planned with SORT as the
basic tier; the folder did not exist. This adds it, following the same
three-layer shape the rest of the suite uses (trackers / datasets /
evaluator) and consuming ngdet.Detection rather than detecting anything
itself, so a sequence can be re-tracked under a different detector
without touching the tracker.
Contents
trackers/base.py TrackResult + BaseTracker + TRACKER_REGISTRY +
build_tracker + iou_matrix, mirroring
ngdet.detectors.base and depth.estimators.base
trackers/sort.py @register("sort") -- constant-velocity Kalman filter
over (cx, cy, area, aspect) plus Hungarian assignment
on IoU. Matches below the gate are rejected AFTER the
assignment so it stays globally optimal
datasets.py MOTChallenge csv reader plus a synthetic generator, so
the module runs with no dataset at all
evaluator.py CLEAR-MOT: MOTA / MOTP / IDF1 / ID-switches, counters
summed across sequences and the ratios formed once
(the MOTChallenge convention)
run_eval.py CLI in the same shape as depth/run_eval.py
numpy and scipy only: no network, no weights, no GPU, nothing to download.
That is deliberate -- the tracking arm stays reproducible by anyone, and a
later appearance-based backend has a like-for-like reference to beat.
Measured, 2 x 30 frames x 4 objects, --min-hits 1 --max-age 3:
condition MOTA MOTP IDF1 IDSW FN
clean +1.0000 1.0000 1.0000 0 0
6 px detector jitter +1.0000 0.9187 1.0000 0 0
10 % missed detections +0.9000 1.0000 0.9474 0 24
15 % missed + 8 px +0.8583 0.8914 0.7175 0 34
Jitter costs MOTP and leaves MOTA's detection terms alone; missed
detections cost MOTA in proportion. Reporting both keeps those separable.
Tests: 37, ~1.2 s, no GPU and no dataset. Line coverage is 100% of the
importable code in all four modules (the only uncovered lines are the
`if __name__` self-test blocks, which each run under `python -m`). They
were checked against 18 seeded mutations -- gate removal, assignment sign,
id reuse, area/aspect swap, the area clamp, IoU union, the ID-switch
counter, MOTA's terms, both MOTChallenge conversions -- and all 18 turn
the suite red.
Two limits are stated in the README rather than left implicit: SORT has no
re-identification, so an object that leaves and returns takes an ID-switch;
and it inherits every miss of the detector it is given.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ngperception/README.mdlists Tracking (MOT) asplanned, with SORT as the basic tier and DeepSORT → ByteTrack → OC-SORT above it. The folder does not exist yet. This adds it.It follows the three-layer shape the rest of the suite uses (trackers / datasets / evaluator) and consumes
ngdet.Detectionrather than detecting anything itself — so a sequence can be re-tracked under a different detector without touching the tracker, which is what keeps the ablation about association rather than detection.Layout
numpyandscipyonly — no network, no weights, no GPU, nothing to download. That is deliberate: the tracking arm stays reproducible by anyone, and a later appearance-based backend gets a like-for-like reference to beat.Runs with no dataset
python -m DeepDataMiningLearning.ngperception.tracking.run_eval \ --trackers sort --synthetic --min-hits 1Dial in the failure the tracker is supposed to survive (2 × 30 frames × 4 objects,
--min-hits 1 --max-age 3):Jitter costs MOTP and leaves MOTA's detection terms alone; missed detections cost MOTA in proportion. Reporting both keeps those separable.
On a MOTChallenge dataset
python -m DeepDataMiningLearning.ngperception.tracking.run_eval \ --trackers sort --root /data/MOT17 --sequences MOT17-02 MOT17-04datasets.pydoes the two conversions that format needs, in one place, tested: frames are 1-indexed on disk, 0-indexed in the API, and boxes are xywh on disk, xyxy everywhere inngdet/ngperception(x2 = left + width, notleft + width − 1). Rows whoseconfis0are MOTChallenge's ignore flag and are dropped by default.Algorithm
A constant-velocity Kalman filter per track over
[cx, cy, area, aspect]with aspect held constant — SORT's own simplification, kept so this is the published baseline and not a private variant — plus Hungarian assignment on IoU between each track's predicted box and each detection. Matches below the gate are rejected after the assignment, not before: filtering first would let a leftover pair win an assignment the optimal solution had given to a better one.Tests
37 tests, ~1.2 s, no GPU and no dataset. Line coverage is 100 % of the importable code in all four modules — the only uncovered lines are the
if __name__self-test blocks, and each of those runs underpython -m.They were checked against 18 seeded mutations: gate removal, assignment sign, id reuse, area/aspect swap, the area clamp, the IoU union term, the ID-switch counter, MOTA's terms, and both MOTChallenge conversions. All 18 turn the suite red.
Two of those started out undetected and the tests were strengthened until they were not — removing the association gate, and removing the area clamp. The first needed a case where a far-away detection must not claim an existing track; the second needed a box collapsing fast enough that the predicted area passes through zero (with the clamp it stays ~240 px wide, without it every corner lands on the same point).
What this baseline does not do
Stated in the README rather than left implicit: SORT has no re-identification, so an object that leaves and returns gets a new id and the sequence takes an ID-switch; it has no occlusion reasoning beyond coasting for
max_ageframes; and it inherits every miss of the detector it is given.The README task-table row moves from
plannedto✅ baseline, with the three appearance/association backends above it still marked planned.🤖 Generated with Claude Code