Skip to content

refactor: centralize geometry-aware dispatch for detection_area and detection_iou - #2374

Merged
Borda merged 13 commits into
roboflow:developfrom
mvanhorn:fix/2318-geometry-aware-dispatch
Jul 21, 2026
Merged

refactor: centralize geometry-aware dispatch for detection_area and detection_iou#2374
Borda merged 13 commits into
roboflow:developfrom
mvanhorn:fix/2318-geometry-aware-dispatch

Conversation

@mvanhorn

Copy link
Copy Markdown
Contributor
Before submitting
  • Self-reviewed the code
  • Updated documentation, follow Google-style
  • Added/updated tests

Description

Centralizes the "which geometry is the real one?" dispatch for detection area and IoU into a single internal module so the mask -> OBB -> box precedence lives in one place instead of being re-implemented (and silently forgotten) at each call site.

Type of Change

  • 🔨 Refactoring (no functional changes)

Motivation and Context

A recurring "silent AABB" bug class keeps reappearing: code reaches for detections.xyxy and forgets the real geometry lives in data["xyxyxyxy"] (OBB) or mask. Because xyxy is always present, the axis-aligned answer is the silent default. Recent fixes (#2306 area returning AABB area, #2303 with_nms/with_nmm dropping crossed OBBs via AABB IoU, #2289 as_yolo dropping OBB rotation) share this root cause: every consumer re-derives geometry precedence and forgetting it fails silently.

@kounelisagis endorsed (2026-06-17) keeping the policy internal ("exact when richer geometry is present") behind a single geometry-resolution helper rather than a public per-op mode argument, and suggested a metamorphic test.

This PR is a deliberate first slice of the multi-part issue: the read-only dispatch helpers plus the contract test land first. move_detections consolidation and the with_nms/with_nmm/as_yolo call-site migration are left as independent follow-ups per the issue's incremental rollout.

Refs #2318

Changes Made

  • Add internal src/supervision/detection/utils/geometry.py with two batched, read-only helpers: detection_area (mask sum / CompactMask.area -> shoelace OBB area -> box_area) and detection_iou (mask_iou_batch -> oriented_box_iou_batch -> box_iou_batch, by the richest geometry both operands carry).
  • Route Detections.area in core.py through detection_area so the property is a thin call into the shared helper, with no behavior change and the vectorized design preserved.
  • Add tests/detection/utils/test_geometry.py: area-parity across mask/OBB/AABB plus the metamorphic contract (identical envelopes with different OBB corners must differ; rotating an OBB off-axis leaves detection_area invariant while the envelope area changes).

Testing

Added tests/detection/utils/test_geometry.py covering area parity (mask/OBB/AABB), the metamorphic rotation-invariance contract, empty Detections, CompactMask routing, and the AABB IoU fallback. The helpers are read-only and preserve Detections.area behavior exactly.

Note: I was unable to run the full suite in my local sandbox (the test stack pulls cv2/matplotlib, which aren't installed in my environment); the new tests are written to run under the repo's CI. Happy to adjust if CI surfaces anything.

Google Colab (optional)

N/A

Screenshots/Videos (optional)

N/A (internal refactor; no user-visible output change)

Additional Notes

The new helpers are intentionally module-private (no public API surface, no per-op mode argument) to match the maintainer's stated preference. Follow-ups can migrate with_nms/with_nmm/as_yolo and consolidate move_detections onto the same dispatch.

@CLAassistant

CLAassistant commented Jun 29, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes geometry-precedence dispatch (mask → OBB → AABB) for per-detection area and pairwise IoU into a single internal helper module, then routes Detections.area through that shared implementation to reduce recurring “silent AABB fallback” regressions.

Changes:

  • Added internal detection_area(...) and detection_iou(...) helpers under src/supervision/detection/utils/geometry.py.
  • Refactored Detections.area to delegate to detection_area (removing duplicated dispatch logic in core.py).
  • Added contract-style tests ensuring area/IoU respect richer geometry and catch envelope-vs-OBB regressions.

Review scores (1–5):

  • Code quality: 4/5
  • Testing: 5/5
  • Documentation: 4/5

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/supervision/detection/utils/geometry.py Introduces centralized geometry-aware dispatch helpers for area and IoU.
src/supervision/detection/core.py Refactors Detections.area to call the shared helper.
tests/detection/utils/test_geometry.py Adds parity + metamorphic/contract tests for dispatch correctness across mask/OBB/AABB.

Comment thread src/supervision/detection/utils/geometry.py Outdated
@Borda
Borda marked this pull request as draft June 30, 2026 23:23
@Borda

Borda commented Jun 30, 2026

Copy link
Copy Markdown
Member

Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.

@mvanhorn mind check this out ^^ 🦝

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87%. Comparing base (89d49c2) to head (d2ea66e).

Additional details and impacted files
@@           Coverage Diff           @@
##           develop   #2374   +/-   ##
=======================================
  Coverage       87%     87%           
=======================================
  Files           84      85    +1     
  Lines        11838   11855   +17     
=======================================
+ Hits         10251   10277   +26     
+ Misses        1587    1578    -9     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Borda and others added 2 commits July 20, 2026 20:21
- Route deprecated inner merges through shared OBB/mask/AABB dispatch
- Add mixed-geometry regression coverage and vectorized mask-area docs

---

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Borda and others added 5 commits July 20, 2026 21:05
[resolve group] PR roboflow#2374 — items 1, 2, 3, 7

Detection_area's dense-mask branch now delegates to the shared
count_mask_pixels SIMD-popcount helper instead of a duplicated
np.count_nonzero(axis=(1,2)) reduction, restoring the ~6x fast path
also used by metrics.utils.object_size (item roboflow#1).

Relocates detection_area/detection_iou from the pure-array
detection/utils/ package to detection/geometry_dispatch.py, since
both consume Detections objects rather than raw arrays — this also
resolves the module-name collision with the top-level
supervision.geometry package (item roboflow#2, item roboflow#7's module-rename part).

Documents detection_iou's shared-geometry, box-IoU-last-resort
fallback and its asymmetry vs detection_area's per-operand dispatch
(item roboflow#3). Renames detection_iou's detections_true/detections_detection
params to detections_a/detections_b — the sole caller passes two peer
merge candidates with no true/pred relationship (item roboflow#7's param-rename
part).

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
[resolve group] PR roboflow#2374 — items 4, 5, 7

Splits the changelog bullet that fused the merge-IoU bugfix with the
unrelated mask-area perf change into two, names the affected APIs, adds
the PR link, and drops the "batched reduction" framing that
mischaracterized a measured regression as an improvement (item roboflow#4).
Restores the blank line before ### Added that this PR's diff had
removed (item roboflow#7's changelog part).

Rewords the confusing filter_detections.md sentence so "if oriented-box
coordinates are present" reads as a condition rather than the data
field acting as the sentence's subject (item roboflow#5).

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
[resolve group] PR roboflow#2374 — item 6

Adds a regression guard asserting detection_area's dense-mask branch
delegates to count_mask_pixels rather than reimplementing it, empty
CompactMask (N=0) coverage through detection_area, degenerate
(collinear, zero-area) OBB coverage through both detection_area and
detection_iou, and a 3-detection merge_inner_detections_objects chain
covering the per-iteration detection_iou call as geometry richness
changes mid-chain (OBB pair merges, then falls back to box IoU against
an AABB-only third detection).

Updates the moved test file's import path to
supervision.detection.geometry_dispatch.

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
@Borda
Borda marked this pull request as ready for review July 20, 2026 22:59
@Borda
Borda requested a review from Copilot July 20, 2026 22:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Comment thread tests/detection/test_geometry_dispatch.py Outdated
Comment thread tests/detection/test_core.py Outdated
Comment thread docs/changelog.md Outdated
Comment thread src/supervision/detection/core.py
Comment thread src/supervision/detection/_geometry_dispatch.py
Borda
Borda previously approved these changes Jul 20, 2026
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…e tests

A prior docstring-collapse edit left two test methods with an
unindented triple-quoted string immediately after `def ...():`,
raising IndentationError at import time and breaking pytest
collection for both files.

[resolve group] PR roboflow#2374 — pre-existing regression found during
resolve baseline check (not a review action item)
Borda added 2 commits July 21, 2026 10:42
`geometry_dispatch.py` sat at a top-level, non-underscored path
under `detection/`, making it directly importable
(`supervision.detection.geometry_dispatch`) despite the PR's stated
intent that these dispatch helpers stay module-private with no
public API surface. Renamed to `_geometry_dispatch.py`, the standard
convention for signalling "internal, not part of the public API,"
and updated the two import sites.

[resolve group] PR roboflow#2374 — item roboflow#6 (@Copilot,
roboflow#2374 (comment))
…aware-dispatch

# Conflicts:
#	src/supervision/detection/core.py
@Borda
Borda merged commit 25e879e into roboflow:develop Jul 21, 2026
23 checks passed
@mvanhorn

Copy link
Copy Markdown
Contributor Author

Thanks for shepherding the refactor, @Borda - geometry-aware dispatch living in one place beats four copies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants