Skip to content

fix: is_empty() returns False for empty tracker arrays#2209

Merged
Borda merged 8 commits intoroboflow:developfrom
abritton2002:fix/is-empty-tracker-id
Apr 13, 2026
Merged

fix: is_empty() returns False for empty tracker arrays#2209
Borda merged 8 commits intoroboflow:developfrom
abritton2002:fix/is-empty-tracker-id

Conversation

@abritton2002
Copy link
Copy Markdown
Contributor

Summary

Fixes #2195.

is_empty() incorrectly returned False on genuinely empty Detections objects when tracker_id was an empty numpy array rather than None.

Root cause: The previous implementation compared self against Detections.empty() via __eq__, which uses np.array_equal. When a Detections object with tracker_id set is filtered to zero results, tracker_id becomes np.array([]) (not None). np.array_equal(np.array([]), None) returns False, so the equality check failed and is_empty() returned False.

Fix: Replace the comparison-based approach with a direct length check on self.xyxy, which is the canonical source of truth for detection count:

# before
def is_empty(self) -> bool:
    empty_detections = Detections.empty()
    empty_detections.data = self.data
    empty_detections.metadata = self.metadata
    return bool(self == empty_detections)

# after
def is_empty(self) -> bool:
    return len(self.xyxy) == 0

Test plan

  • Added 4 parametrized regression tests in tests/detection/test_core.py::test_is_empty
    • Canonical Detections.empty()True
    • Non-empty detections without tracker_idFalse
    • Filtered-to-empty detections with tracker_id (the regression case) → True
    • One detection remaining after filter → False
  • All tests pass: uv run python -m pytest tests/detection/test_core.py::test_is_empty -v

🤖 Generated with Claude Code

…ow#2195)

Previously, is_empty() compared self to Detections.empty() via __eq__,
which uses np.array_equal. When tracker_id is an empty numpy array
(rather than None), np.array_equal(np.array([]), None) returns False,
causing is_empty() to incorrectly return False on genuinely empty
Detections objects.

Fix: replace the equality-comparison approach with a direct len() check
on self.xyxy, which is the canonical source of truth for detection count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@abritton2002 abritton2002 requested a review from SkalskiP as a code owner April 10, 2026 17:53
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 10, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes sv.Detections.is_empty() incorrectly returning False for filtered-to-empty detections when tracker_id is an empty NumPy array (instead of None), aligning emptiness with the canonical detection count (xyxy length).

Changes:

  • Reimplemented Detections.is_empty() to use len(self.xyxy) == 0 rather than equality vs Detections.empty().
  • Added parametrized regression tests covering empty/non-empty cases including the tracker_id filtered-to-empty scenario.
  • Expanded the is_empty() docstring to describe semantics and provide an example.

Reviewed changes

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

File Description
src/supervision/detection/core.py Updates is_empty() implementation and docstring to define emptiness by xyxy length.
tests/detection/test_core.py Adds regression coverage for is_empty() including the tracker_id empty-array case.

Comment thread src/supervision/detection/core.py Outdated
Borda and others added 4 commits April 13, 2026 12:27
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Case 4: [TEST_DET_NONE] now returns Detections.empty() — zero-length xyxy is empty
- Case 8: [TEST_DET_ZERO_LENGTH x2] now returns Detections.empty() — same reason
- Case 9: [TEST_DET_1, TEST_DET_NONE] now returns TEST_DET_1 with DoesNotRaise() —
  the ValueError was an artifact of the bug; empty operand is now stripped before
  merge's field-compatibility check, so merge succeeds cleanly

[resolve roboflow#2] /review finding by sw-engineer + qa-specialist (report: .temp/output-review-fix-is-empty-tracker-id-2026-04-13.md)
[resolve roboflow#4] /review finding by sw-engineer (report: .temp/output-review-fix-is-empty-tracker-id-2026-04-13.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
- Add filtered_empty_with_mask parametrize case (same bug applies to mask field)
- Add explicit ids= for readable pytest output
- Add one-line docstring to test function

[resolve roboflow#5] /review finding by qa-specialist (report: .temp/output-review-fix-is-empty-tracker-id-2026-04-13.md)
[resolve roboflow#6] /review finding by qa-specialist (report: .temp/output-review-fix-is-empty-tracker-id-2026-04-13.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78%. Comparing base (6b5eed2) to head (8244808).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff           @@
##           develop   #2209   +/-   ##
=======================================
- Coverage       78%     78%   -0%     
=======================================
  Files           63      63           
  Lines         7977    7972    -5     
=======================================
- Hits          6253    6248    -5     
  Misses        1724    1724           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes sv.Detections.is_empty() incorrectly returning False for “filtered-to-empty” detections when optional fields (e.g., tracker_id, mask) are present as empty arrays instead of None, by making emptiness depend solely on detection count (xyxy length).

Changes:

  • Simplified Detections.is_empty() to return len(self.xyxy) == 0.
  • Updated merge-related expectations in tests/detection/test_core.py now that truly empty detections are correctly recognized and ignored by Detections.merge.
  • Added parametrized regression tests for is_empty() covering the tracker_id empty-array case (and a similar mask case).

Reviewed changes

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

File Description
src/supervision/detection/core.py Replaces equality-based emptiness detection with an xyxy length check and expands the docstring.
tests/detection/test_core.py Adds regression tests for is_empty() and updates merge test expectations to align with corrected emptiness handling.

Comment thread src/supervision/detection/core.py Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@Borda
Copy link
Copy Markdown
Member

Borda commented Apr 13, 2026

is_empty() Robustness Across Detection Types

Detection type xyxy always populated? is_empty() correct?
Bounding box Yes — required field
OBB Yes — axis-aligned wrapper always set
Segmentation (dense mask) Yes — computed via mask_to_xyxy()
Segmentation (CompactMask) Yes — same, never materialized ✓ + O(1)
VLM outputs (polygons, etc.) Yes — connectors compute xyxy first
Empty (cls.empty()) Yes — (0, 4) shape
KeyPoints N/A — separate class ⚠ same old bug, unfixed

@Borda Borda force-pushed the fix/is-empty-tracker-id branch from 2a76c30 to 8244808 Compare April 13, 2026 13:51
@Borda Borda merged commit e19f312 into roboflow:develop Apr 13, 2026
24 checks passed
@Borda Borda mentioned this pull request Apr 17, 2026
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.

[Bug]: Inconsistent behavior of sv.Detections.is_empty() if tracker_id is not None

4 participants