Repository navigation
feat: expose sv.match_detections as a public matching primitive - #2557
Conversation
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
sv.match_detections as a public matching primitive
There was a problem hiding this comment.
🟡 Changes recommended
The public API currently accepts invalid IoU thresholds, which can pair unrelated detections or fail silently.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Exposes the metrics’ greedy IoU matcher as the public sv.match_detections API.
Changes:
- Adds one-to-one matching with class-aware and class-agnostic modes.
- Adds comprehensive tests and public export.
- Adds API documentation, navigation, and changelog entry.
Assessment: 🟠 Request Changes
Quality: Code 4/5 · Testing 4/5 · Documentation 5/5 · Risk 2/5
Invalid IoU thresholds require validation and a regression test.
File summaries
| File | Description |
|---|---|
src/supervision/metrics/utils/matching.py |
Implements the public matcher. |
src/supervision/__init__.py |
Exports match_detections. |
tests/metrics/utils/test_matching.py |
Tests matching behavior and edge cases. |
docs/metrics/match_detections.md |
Adds API usage documentation. |
mkdocs.yml |
Adds the documentation page to navigation. |
docs/changelog.md |
Records the new public API. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
6ceb082 to
22f46fa
Compare
Add a public API that matches two sets of detections into one-to-one pairs, reusing the same greedy highest-IoU-first matcher the metrics modules use internally. match_detections(detections_a, detections_b, iou_threshold=0.5, class_agnostic=False) returns index arrays: matched_pairs of shape (M, 2) plus the unmatched indices of each side, so the result composes with Detections slicing. By default a pair also requires equal class_id; class_agnostic=True restricts matching to IoU. confidence is ignored. Empty inputs return an empty (0, 2) pair array with every index of the other side unmatched. Export it as sv.match_detections, add unit tests, a docs page under metrics, and a changelog entry. Closes roboflow#2476. Signed-off-by: jabrailkhalil <[email protected]>
22f46fa to
0be8018
Compare
|
@jabrailkhalil pls avoid force push, otherwise you destroy our review process and cannot move forward... |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #2557 +/- ##
=======================================
Coverage 89% 89%
=======================================
Files 86 86
Lines 11877 11908 +31
=======================================
+ Hits 10619 10650 +31
Misses 1258 1258 🚀 New features to boost your workflow:
|
Changes: - Validate public match_detections IoU thresholds before empty-input handling using the shared range validator. - Add invalid-threshold regression coverage and the required maintainer module documentation. Impact: - Disjoint detections can no longer be falsely paired by a negative threshold; invalid thresholds consistently raise ValueError. - Maintainers have an explicit module boundary and failure contract for the public matcher. Verification: - Focused matcher tests and doctests: 21 passed. - Ruff check, Ruff format check, and git diff --check: passed. Residual limits: - Independent QA/challenger evidence for PR roboflow#2557 remains unresolved; this commit fixes only local source findings. --- Co-authored-by: Codex <[email protected]>
Changes: - Move the public detection matcher and its tests from metrics utilities to detection utilities, updating metric consumers and documentation references. - Require class IDs for non-empty class-aware matching and document explicit geometry-only opt-in plus greedy non-optimal assignment behavior. Impact: - sv.match_detections keeps its top-level API while its module ownership now matches the Detections domain. - Callers cannot silently weaken class-aware matching when class metadata is absent. Verification: - Focused matcher, precision, and recall tests plus matcher doctests: 85 passed. - Ruff check, Ruff format check, and git diff --check: passed. Residual limits: - Codemap query was unavailable because its launcher requires Python 3.11+ while this workspace uses Python 3.10. - Independent QA/challenger evidence for PR roboflow#2557 remains unresolved. --- Co-authored-by: Codex <[email protected]>
Changes: - Validate class IDs before the empty-input fast path for class-aware detection matching. - Add regression coverage for empty class-aware inputs and preserve explicit geometry-only matching. Impact: - class_agnostic=False now consistently rejects missing class metadata, preventing any implicit geometry-only fallback. Verification: - Focused matcher, precision, and recall tests plus matcher doctests: 86 passed. - Ruff check, Ruff format check, and git diff --check: passed. Residual limits: - Independent QA/challenger evidence for PR roboflow#2557 remains unresolved. --- Co-authored-by: Codex <[email protected]>
…lil/supervision into feat/match-detections
- Ensure `detections_a.class_id` and `detections_b.class_id` are not `None` before comparison to prevent silent failures in class-aware detection matching. - Maintain consistent behavior for `class_agnostic=False` by asserting required metadata.
Summary
Exposes the greedy matcher that the metrics modules use internally as a public, stateless primitive:
sv.match_detections.matched_pairshas shape(M, 2): column 0 indexesdetections_a, column 1 indexesdetections_b;unmatched_a/unmatched_bhold the remaining indices of each side. The result composes withDetectionsslicing (detections_b[matched_pairs[:, 1]], etc.)._greedy_matchfrom fix(metrics): replace np.unique matching with greedy algorithm #2380. Ties keep the stablenp.argsort(-iou, kind="stable")order.class_id;class_agnostic=Truematches on IoU only. If either side has noclass_id, matching falls back to IoU only.iou_thresholdare never matched;confidenceis ignored.(0, 2)pair array and the other side's indices as unmatched.No metric behavior changes: the implementation only wraps
box_iou_batch+_greedy_match.Tests
Added
TestMatchDetectionsintests/metrics/utils/test_matching.py(8 cases): identical pairing, unmatched-index reporting, class mismatch blocking by default,class_agnostic=True, IoU threshold filtering, one-to-one assignment under contested predictions, empty inputs, and missingclass_idfallback. The docstring example also runs under--doctest-modules.Documentation
docs/metrics/match_detections.mdwith usage and API reference; added to the Metrics nav inmkdocs.yml.Verification
Closes #2476.