Commit Graph

154 Commits

Author SHA1 Message Date
Daniiiil1 6b143e4e41
test(metrics): verify live sklearn parity (#2470)
* add sklearn parity goldens
* compute sklearn parity live
* separate empty input semantics
2026-08-05 19:24:44 +02:00
Arthi Arumugam 7fc91180fe
fix(metrics): track prediction-only classes in Recall (#2468)
#2331 made Precision and F1Score include classes that appear only in
predictions, and added regression tests to both. Recall was not touched, so
the line #2331 replaced is still there and the three metrics disagree about
which classes exist for identical input:

    precision.matched_classes -> [0 1]   precision_per_class (2, 10)
    recall.matched_classes    -> [0]     recall_per_class    (1, 10)
    f1.matched_classes        -> [0 1]

These read as parallel outputs, so zipping them silently truncates rather
than raising.

Recall for a class with no ground-truth instances is 0.0 rather than
undefined, which is what sklearn reports (it infers labels from the union of
y_true and y_pred) and what #2331 cited as its own standard. MICRO is
unchanged because an absent class contributes no false negatives, and
WEIGHTED is unchanged because its ground-truth support is zero. MACRO does
change, and the changelog says so.

Also of note: recall.py already carried #2331's WEIGHTED zero-support guard,
whose comment refers to 'only false-positive classes'. That state could not
arise in recall.py, because unique_classes came from ground truth alone. The
guard was propagated; the union that gives it meaning was not.

Addresses the review on #2468. Building the class union inside
_compute_recall_for_classes only covers samples that reach it, and samples with
predictions but no targets are skipped earlier in _compute. So matched_classes
could still disagree with Precision and F1Score for list inputs containing a
background image, which is the exact invariant the new test asserts.

Before, for one normal sample plus one background image predicting class 2:

    precision.matched_classes -> [0 2]
    recall.matched_classes    -> [0]

Recall now handles len(targets) == 0 and len(predictions) > 0 the way Precision
does. No recall value changes, since a background image produces no false
negatives; only the tracked class set does.

* test: cover Recall bg-image size-bucket, dup & non-contiguous ids
* docs: strengthen Recall changelog migration note
* docs+perf: Recall doctest example; dedupe-then-union micro-opt

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-08-03 20:57:05 +02:00
Jirka Borovec f2efc328f7
fix(dataset): 3D empty mask for VOC background (#2469)
- `detections_from_xml_obj` now builds `np.empty((0, H, W))` for a background image under `force_masks=True` instead of letting `np.array([])` collapse to shape `(0,)`, which failed `Detections` mask validation
- document the forced `class_id` `dtype=int` with an inline comment and state the integer-dtype guarantee in the `detections_from_xml_obj` docstring Returns section
- add background-image coverage: force_masks empty 3D mask, all-background dataset, background-first ordering, and save-then-load round-trip
- add changelog entry for the `force_masks=True` background-image mask fix

---

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-08-03 18:30:24 +02:00
shao 475d551908
refactor: vectorize `get_labels_text()` in annotators/utils (#2465)
* refactor: vectorize `get_labels_text()` in annotators/utils.py
* test: add tests for all get_labels_text branches
* style: flatten elif/else to guard clauses in get_labels_text()
* refactor: guard get_labels_text() against array/detections length mismatch
* test: add missing get_labels_text() coverage

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-08-03 17:43:14 +02:00
Shadow_Lu 1a2b9b24db
fix(dataset): keep `class_id` integral for VOC background images (#2463)
detections_from_xml_obj built class_id with np.array(...) over a list of
indices. For an annotation file with no object elements that list is empty,
so NumPy inferred float64 and DetectionDataset validation rejected the
resulting Detections, making any Pascal VOC dataset that contains an
unannotated image impossible to load.
2026-08-03 12:17:01 +02:00
Jirka Borovec 794971ba0f
feat(cv2): remove OpenCV dependency (#2443)
* feat(cv2): remove OpenCV dependency
* ci(tests): cover ambient cv2 wheels
* fix(cv2): restore fallback CI
* ci(tests): simplify pytest job name formatting
* ci(tests): refactor cv2 backend check for readability and set Python shell explicitly
* test(cv2): stabilize OpenCV parity checks
* ci(tests): fix Python 3.13 matrix typo in CI workflow
* scope OpenCV-absence check to declared deps/extras
* normalize whitespace in release-doc phrase assertions
* fix(ci): strip manifest line before comment check
* emit `UserWarning` when OpenCV is missing to alert users of fallback behavior

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-31 22:19:33 +02:00
Erik 541b0226cd
feat: add image URL loader (#2372)
- Added image loading from HTTP and HTTPS URLs with descriptive URL validation errors
- Added optional caching for image URL loads using the shared Supervision cache
- Improved URL downloads with atomic file replacement and shared download behavior across image loading and asset downloads
- Updated image decoding compatibility with Pillow fallbacks when OpenCV decoding or encoding is unavailable

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-28 21:24:55 +02:00
Andrew Barnes e138f6c544
Fix sink state when instances are reopened (#2459)
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
2026-07-28 10:11:06 +02:00
pre-commit-ci[bot] 5f0654e5cc
chore(pre_commit): ⬆ pre_commit autoupdate (#2460)
* chore(pre_commit): ⬆ pre_commit autoupdate

updates:
- [github.com/rbubley/mirrors-prettier: v3.9.5 → v3.9.6](https://github.com/rbubley/mirrors-prettier/compare/v3.9.5...v3.9.6)
- [github.com/tox-dev/pyproject-fmt: v2.25.3 → v2.26.0](https://github.com/tox-dev/pyproject-fmt/compare/v2.25.3...v2.26.0)
- [github.com/astral-sh/ruff-pre-commit: v0.15.22 → v0.16.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.22...v0.16.0)

* test(detection): fix type hint for `expected_results` in VLM tests

* fix(pre_commit): 🎨 auto format pre-commit hooks

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
2026-07-28 10:01:41 +02:00
Piotr Skalski 9837c17878
feat(vlm): add Gemini 3.5 Flash parsing support (#2449)
Add VLM.GOOGLE_GEMINI_3_5 enum and from_google_gemini_3_5 connector reusing the 2.5 parser, wire it into Detections.from_vlm, and salvage valid entries from partially malformed Gemini JSON arrays. Includes tests and changelog.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
2026-07-21 16:20:05 +02:00
Mahbod b20d6eac46
feat(utils): add prefetch to `get_video_frames_generator` (#2273)
* feat(utils): add prefetch to get_video_frames_generator
* fix(utils): harden _prefetched_frames_generator threading safety
* test(utils): add prefetch combination and minimum-queue tests
* docs(utils): improve prefetch documentation, validation, and test docstrings
* fix(utils): harden prefetch reader-thread exception handling + docs
* docs(changelog): sync front-matter date_modified
* test(utils): harden and extend prefetch test coverage
* test(utils): cover buffered-frames-before-error and zero-frame prefetch cases

---------

Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-21 14:12:08 +02:00
Matt Van Horn 25e879ec05
refactor: centralize geometry-aware dispatch for detection_area and detection_iou (#2374)
* refactor: centralize geometry-aware dispatch for detection_area and detection_iou
* fix(detection): centralize geometry-aware merge IoU
* docs(detection): add code examples to geometry calculation docstrings
* code: reuse count_mask_pixels; relocate geometry dispatch out of utils/
* docs: fix changelog framing and filter_detections.md wording
* test: add edge-case coverage for geometry dispatch and merge chains
* fix(tests): repair syntax-broken docstrings in geometry dispatch/merge tests
* refactor(detection): make geometry dispatch module private

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-21 12:37:20 +02:00
HALLOUARD 89d49c2e93
feat: Add soft Non-Max suppression (#1624)
* feat: Add soft Non-Max suppression
* feat(nms): add vectorized Gaussian Soft-NMS box/mask primitives
* feat(core): add Detections.with_soft_nms
* feat: export soft-NMS functions from top-level supervision API
* docs: add soft-NMS entries to IoU/NMS utils page
* test: add Soft-NMS coverage for box/mask primitives and Detections API

---------

Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-21 10:25:14 +02:00
Mahbod 937ed4af37
feat(detection): add require_all_anchors to PolygonZone (#2272)
Currently a detection counts as 'in the zone' only when every anchor in
triggering_anchors is inside. For boxes that straddle the zone boundary
this means a detection with many anchors (e.g. the four corners) is often
under-counted unless the user shrinks triggering_anchors to a single point.

Add require_all_anchors: bool = True so callers can opt into 'any anchor
inside is enough'. Default preserves current behaviour.

* test: strengthen PolygonZone require_all_anchors coverage
* docs: clarify require_all_anchors anchor-based semantics

---------

Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-17 18:56:42 +02:00
Lee Clement 60d748e57d
fix: read COCO export image sizes from headers instead of decoding pixels (#2442)
save_coco_annotations iterated the dataset, cv2-decoding every image only
to read its shape — even for labels-only exports. Sizes now come from the
in-memory array when present, else a lazy PIL header read, the same
optimization from_yolo uses (#1636).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
2026-07-17 18:30:24 +02:00
Jirka Borovec f7b63f149a
perf(cv2): simplify fallback operations (#2441)
- Remove unused compatibility operations and use focused Pillow and NumPy paths to reduce maintained fallback code.
- Preserve numerical decisions and hot-path performance with exact regression coverage and bounded algorithms.
- Preserve INTER_LINEAR uint8 reductions within one LSB while retaining the resize performance budget and numeric RGBA handling.
- Restore repeated-endpoint contour anchors and bound cross-platform chamfer coefficient drift in regression tests.

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-17 17:31:57 +02:00
Shehzad Waseem 9aaf7fdbd6
fix(metrics): avoid division by zero RuntimeWarning in F1Score using np.divide (#2437)
* fix(metrics): avoid division by zero RuntimeWarning in F1Score using np.divide
* test+changelog: add F1Score zero-denom regression test; add changelog entry
* follow-up cleanup: mirror F1Score np.divide fix in mean_average_recall

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-17 17:11:45 +02:00
jirka a4b9c4e097 fix(cv2): pad getTextSize height/baseline from actual stroke_width
_get_text_size approximated thickness-to-stroke padding with
thickness // 2 formulas that diverge from the thickness - 1
stroke_width _put_text actually renders with. Past thickness 2 the
padding grows too slowly, so heavy-stroke descender pixels can fall
outside the reported box, breaking the documented enclosure
guarantee. Both functions now derive stroke_width from one shared
helper.

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-17 10:29:55 +02:00
Jirka Borovec 68e63f9e39
refactor(cv2): replace Hershey text with Pillow (#2440)
Text fallback now renders through Pillow with the DejaVu Sans face
resolved via matplotlib font_manager, replacing the Hershey stroke-font
reader; getTextSize metrics derive from the same font and differ from
OpenCV within the documented visual-divergence tier.

Remove the packaged Hershey glyph data (hershey_fonts.json, provenance,
license) and its _cv2/data package-data entry.

Delete unused fallbacks: _geometry _fill_poly and _point_in_polygon
(live fillPoly is the Pillow one in _drawing) and _common _unavailable.

Replace test_hershey with Pillow-oriented test_text, drop test_common,
and point test_contours/test_geometry at _drawing._fill_poly. Document
the fallback text-backend change in the changelog.

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-17 10:22:32 +02:00
Jirka Borovec 1efa5b8eaa
feat(cv2): complete fallback integration (#2439)
* feat(cv2): complete fallback integration
* fallback-fixes: reject invalid addWeighted dtype; O(N) approxPolyDP anchor seeding
* tests: copyMakeBorder sequence parity; drop non-empty facade-import assert; fix Windows path separator in boundary check
* fix(cv2): copyMakeBorder scalar value only fills channel 0 on multichannel images

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-17 07:50:45 +02:00
Jirka Borovec 20b7c085b7
feat(video): require PyAV during cv2 transition (#2438)
- Add the PyAV-backed file-video and audio fallback to the compatibility layer.
- Declare PyAV alongside OpenCV until the final dependency-removal integration.
- _VideoWriter now rejects is_color=False (NotImplementedError) instead of
  silently dropping it, since the PyAV fallback only encodes 3-channel frames.
- _mux_audio cleanup (container closes, temp-file removal) is now best-effort
  so a failing close/remove in finally can no longer mask the primary result
  or the original exception.
- The subprocess used to validate the cv2-free fallback had no timeout;
  a hang (import deadlock, codec probe stall) could block the whole CI
  run. Added a 60s timeout so a hang fails fast with a clear traceback
  instead of an opaque suite-wide stall.
- process_video(preserve_audio=True) docstring still described the old
  ffmpeg-based muxing; audio remuxing was reimplemented with PyAV and no
  longer requires an external ffmpeg executable.
- get_video_frames_generator's documented webcam fallback
  (`_cv2.VideoCapture(0)`) silently fails under the PyAV backend: the
  BackendUnavailableError raised for integer sources was swallowed with no
  logging, so isOpened() just returns False with zero diagnostic signal.
  Doc note now states the limitation explicitly and the capture logs a
  warning instead of failing silently.

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-16 20:13:15 +02:00
Jirka Borovec c3496134bc
feat(cv2): add Hershey text fallback (#2435)
* feat(cv2): add Hershey text fallback
* fix(cv2): sync Hershey provenance hash

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-16 17:10:49 +02:00
Jirka Borovec 39eb6571ce
feat(cv2): add drawing fallbacks (#2433)
* feat(cv2): add drawing fallbacks
* code: reject non-default hierarchy in _draw_contours fallback
* tests: keep cv2 optional so cv2-less fallback tests still run

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-16 12:53:01 +02:00
Jirka Borovec 7096ee911c
feat(cv2): add geometry fallbacks (#2432)
- Added geometry fallbacks for OpenCV-dependent operations, including connected-component processing.
- Fixed contour hierarchy detection for concave shapes by reliably selecting an interior point.
- Improved contour hierarchy remapping performance for large contour sets.

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-16 00:54:57 +02:00
Jirka Borovec 3d669f1ab4
feat(cv2): add image fallback backend (#2431)
- Organize facade constants and implementations into thematic private modules.
- Add NumPy/Pillow/SciPy fallbacks with OpenCV parity coverage.
- Mirror package modules in cv2 tests and verify blocked imports.
- Split compound operation tests into isolated cases.
- Parameterize color parity and fallback bindings for targeted failures.
- Inline color conversion cases at their only use site.
- Inline fallback binding cases while preserving reusable manifests.

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-15 21:55:08 +02:00
Jirka Borovec 8ecd9a6680
refactor(cv2): add optional backend facade (#2430)
* refactor(cv2): add optional backend facade
* test: guard real cv2 oracle import for cv2-less environments
* test: preserve existing PYTHONPATH in subprocess import tests
* lint: auto-fix violations after resolve cycle
* fix(typing): remove obsolete suppressions
* test(cv2): parametrize constant alignment tests and refactor fallback validation
* test(cv2): simplify constant grouping and optimize REQUIRED_SYMBOLS validation

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-15 20:53:24 +02:00
Jirka Borovec 16814acff3
feat(utils): add `TkImageWindow` to unblock switch to `opencv-python-headless` (#2320)
- Added `sv.ImageWindow`, a Tkinter/Pillow-based desktop image viewer with BGR, grayscale, and BGRA support, keyboard polling, left-click callbacks, context-manager usage, window-state checks, and clean close handling
- Added responsive image resizing with optional aspect-ratio preservation and correctly mapped mouse coordinates after scaling or letterboxing
- Updated compatible runnable examples to use `sv.ImageWindow`, while retaining OpenCV display APIs for worker-thread streaming examples that are incompatible with Tkinter
- Improved `sv.cv2_to_pillow` to support grayscale and BGRA images
- Updated webcam guidance to clarify capture ownership and explicit `VideoCapture` cleanup
- Fixed image-window event handling to prevent stale keypresses, ghost windows, close-time races, and blocked waits after the window closes

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-15 15:06:55 +02:00
Abhijith Neil Abraham 94cfb7f290
fix(metrics): ignore out-of-bucket detections in size-bucketed sco… (#2428)
* fix: ignore out-of-bucket   detections in size-bucketed scoring
* fix: honor area metadata in buckets

- Prefer stored COCO area metadata before geometry, mask, or OBB fallbacks.
- Add explicit-area, mask, and OBB regression coverage.
- Align COCO, mAP, and changelog area semantics.

---------

Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
2026-07-15 12:48:19 +02:00
Teïlo M 14c3c86e22
Fix hex parser accepting multiple leading prefixes (#2421)
`hex_to_rgba` previously stripped every leading `#`, so invalid inputs such as `##000000` were accepted despite `is_valid_hex` rejecting them.

Remove only one optional prefix and add regression coverage for the minimized failing input.

Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
2026-07-11 00:55:51 +02:00
Abhijith Neil Abraham 287868e171
feature: add KeyPoints.merge() method (#2412)
* feat: add KeyPoints.merge() method
* docs: address review comments on merge docstring and changelog date
* chore: retrigger CI after transient links-check failure
* ci(links-check): accept transient 5xx responses to stop flaky failures
* test(keypoints): add validation for consistent coordinate depth across skeletons
* docs(keypoints): document coordinate-depth ValueError in merge() Raises
* test(keypoints): add docstring, zero-keypoint, and merge+with_nms coverage

---------

Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-09 21:37:26 +02:00
Jirka Borovec 5344cb99dd
fix: close out remaining review findings (#2418)
Re-verify remaining supervision review backlog against develop HEAD; most items were already resolved by an intervening commit, only genuinely-open gaps got new fixes.
Fix float32 precision loss in box_iou_batch for large coordinates (GeoTIFF-scale) by accumulating in float64.
Raise ValueError instead of a strippable assert in EvaluationDataset.load_predictions for unknown image ids.
Add HeatMapAnnotator.reset() to clear accumulated heat for annotator reuse.
Add missing coverage: labelme export basename collisions, _greedy_match matcher, metrics.core ABC/enum contracts, metrics.utils.utils pandas guard; remove a global RNG-seed pollution site in a metrics test.
Document the last two undocumented public exports (calculate_masks_centroids, is_compressed_rle) and add usage examples to 17 previously-example-less public functions/classes (NMS/NMM helpers, draw utils, PolygonZoneAnnotator, mask/polygon converters).

* tests: load_predictions ValueError branch + empty-dataset coverage
* fix: box_iou_batch int-dtype overflow, narrow float32 precision claim
* feat: add reset() to TraceAnnotator/DetectionsSmoother, fix docstrings
* docs: fix temp file leak in coco.py docstring, rename misnamed test

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-09 17:53:52 +02:00
Jirka Borovec 75023c5f2f
fix: remaining review findings in dataset, docs, and tests (#2416)
- Added `sv.mask_to_roi` as an explicit migration path for exclusive mask bounds
- Fixed COCO, CreateML, and Pascal VOC export validation to reject ambiguous or colliding dataset paths before writing
- Fixed in-memory `DetectionDataset` split and merge behavior
- Fixed `supervision` imports to avoid loading ByteTrack until it is used
- Fixed detection conversion helpers to support coordinate-convention migration while preserving legacy inclusive defaults
- Fixed Azure tag mapping, anchor rounding, and line-zone smoothing to avoid incorrect or ghost detections
- Fixed video processing shutdown handling for timeout and full-queue cases
- Improved downloader, validator, documentation, and regression coverage for the shipped dataset, detection, annotator, image, and video behavior

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-08 23:00:32 +02:00
Jirka Borovec 23a2227ae7
fix(docs): resolve review deprecation follow-ups (#2415)
- Extend active deprecation removals to 0.31.0 and align deprecated API docs, changelog, and warnings.
- Add missing reference docs for VLM, conversion helpers, geometry, metrics extras, and tracker deprecation notices.
- Raise when ImageSink cannot write an image and cover the failure path with a regression test.
- Correct conversion and deprecated docs to match exported names and restore KeyPoints.confidence.
- Add regression coverage for SUPERVISION_DEPRECATION_WARNING precedence and document ImageSink.save_image() failure behavior.

* test: add validation and behavior tests for Color, Position, and polygon approximation adjustments

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-08 14:30:32 +02:00
Jirka Borovec 072f78471c
fix: resolve medium dataset findings (#2408)
- Reinstated NumPy-safe `Classifications` equality and ordered class-list comparisons in dataset equality.
- Restored greedy matching plus size-bucket scoring for Precision, Recall, F1, and MeanAverageRecall, with regression coverage for the medium-object boundary case.
- Filter size-bucket precision, recall, and F1 against target boxes so predictions no longer claim the bucket.
- Preserve confidence order for bucketed mAR@K scoring and return zero when a bucket has no support.
- Add regression coverage for bucket matching, empty-support mAR, top-K limits, and missing-mask errors.

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-08 08:56:34 +02:00
Jirka Borovec 74db9e29ff
fix(utils): normalize timm confidences and verify assets (#2414)
- Convert timm classification logits with softmax so confidence values match the normalized scale used by other classification adapters.
- Verify asset MD5 hashes after fresh downloads and retry once when a payload is corrupted.
- Add focused regressions for timm confidence scaling and asset download integrity paths.
- Convert from_timm outputs to probabilities before applying thresholds and document that existing thresholds may need retuning.
- Add downloader regression coverage for repeated MD5 mismatches so exhausted retries now raise ValueError.

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-07 21:59:23 +02:00
Jirka Borovec dde422703c
fix(tracker): harden ByteTrack edge cases (#2413)
- Keep ByteTrack confidence-threshold boundary detections eligible and avoid impossible activation thresholds above score 1.0.
- Stop mutating caller-owned detections and assignment cost matrices while preserving matched tracker output.
- Filter invalid tensor boxes before Kalman updates and respect minimum consecutive frames on first-frame tensor updates.
- Avoids per-call np.arange allocation by cloning detections with slice(None) while preserving non-mutation behavior.
- Adds regressions for delayed activation on the second consecutive tensor frame and broader invalid-tensor rejection cases.

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-07 21:05:03 +02:00
Jirka Borovec 814a226eba
fix(metrics): harden scoring edge cases (#2411)
- Use COCO 101-point AP averaging in the legacy mAP path so perfect and imperfect curves score consistently.
- Validate confusion-matrix class ids before indexing and preserve target ignore flags in the COCO-style evaluator.
- Keep mAR per-class recall for each max-detection cutoff and cover the scoring fixes with focused regressions.
- Return empty mAR scores with the same max-detection axis as non-empty results.
- Add an empty-input regression covering recall score and per-class result shapes.
- Update the public mAR docstring to describe per-image detection limits.

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-07 18:46:05 +02:00
Jirka Borovec 6a69197177
fix(dataset): harden dataset IO edge cases (#2410)
- Avoid mutating caller-owned Detections during dataset construction and reject invalid class ids with clear ValueErrors.
- Make COCO loading/export tolerant of missing optional metadata, add from_coco(use_iscrowd), and export mask pixel area when needed.
- Let folder-structure and YOLO loading skip common clutter and accept PIL-readable image modes with regression coverage.
- Preserve from_coco positional show_progress compatibility while keeping use_iscrowd keyword-only.
- Filter class-folder loading to image files and export missing COCO mask area from decoded masks.
- Add regression coverage, changelog updates, and types-tqdm for mypy.

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-07 16:29:43 +02:00
Abhijith Neil Abraham 5b4c8b6d0d
fix(key_points): handle empty and numpy index input, keep degenerate skeletons (#2402)
* handle empty and numpy index input, keep degenerate skeletons

- Filter non-finite keypoint coordinates when converting to detections while preserving finite zero-area skeletons.
- Treat zero-length KeyPoints selections as empty and add regression coverage for metadata alignment and selected-index equivalence.

---------

Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
2026-07-07 00:02:38 +02:00
Jirka Borovec c3413a8f10
fix(annotators): resolve annotator medium findings (#2407)
- Added deterministic color lookup with flexible palette resolution and clear errors for empty palettes
- Improved annotator and utility handling for warning formatting, plotting imports, and icon caching
- Added validation for keypoint edges, MediaPipe inputs, and VideoSink state

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-06 22:43:35 +02:00
Jirka Borovec e13090f84b
Fix detection medium review findings (#2400)
- Fixed detection medium findings across adapters, mask non-max merge, sinks, segmentation parsing, LineZone history, and mask ROI handling
- Fixed mask non-max merge deprecation warnings to honor the standard warning opt-out and include version context
- Fixed mask non-max merge validation for invalid IoU thresholds
- Fixed CompactMask non-max merge grouping to update merged mask candidates correctly
- Fixed selected and compacted detections to copy arrays and metadata, preventing mutations from leaking back to source detections
- Fixed LineZone crossing history eviction to tolerate short tracking gaps and evict stale state per tracker/class key
- Fixed semantic segmentation handling to preserve class ID 0
- Improved mask ROI conversion performance by avoiding unnecessary full-frame copies and repeated scans
- Updated JSONSink changelog/docs to document native bool/int/float output while leaving CSVSink unchanged
- Updated detection docstrings for mask parsing, selection copy semantics, validation errors, and argument readability guidance

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-06 19:02:38 +02:00
Jirka Borovec bd0f44fcfd
fix: resolve remaining High findings from deep codebase review (#2389)
- Fixed crop annotation so overlapping detections sample from the original scene
- Fixed dataset exports to reject basename collisions, including case-insensitive collisions
- Fixed LMM connector mapping to support mirror enum aliases without a hand-maintained dispatch table
- Updated benchmark documentation to install the released inference package with metrics support

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-03 22:58:07 +02:00
Jirka Borovec 78aec073c4
test: cover public API gaps and dataset split (#2399)
* test: cover public API gaps and dataset split
* test(sinks): switch VideoSink to AVI/MJPG and add ImageSink clearing test
* test(detection): add box_non_max_merge 6-column class-separation tests
* test(dataset): drop deprecated dict API and strengthen class-id assertion
* test(public_api): strengthen importability check with getattr

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-03 20:57:42 +02:00
Jirka Borovec eea04b3656
fix(detection): harden model connectors and mask extraction (#2398)
- `from_tensorflow` scaled boxes in place on the array returned by `.numpy()`, which can share memory with the source tensor — corrupting caller data and double-scaling on a repeat call; copy before scaling
- `from_lmm` raised a bare `KeyError` for `MOONDREAM` and `QWEN_3_VL`, which the enum and docstring advertise; map both to their `VLM` members
- `from_deepseek_vl_2` returned a `(0,)`-shaped `xyxy` on empty output, so a zero-detection response crashed the `Detections` constructor; return `(0, 4)` like the other parsers
- `extract_ultralytics_masks` binarized bilinear-resized masks with `> 0`, dilating every mask at object boundaries; threshold at 0.5 to match Ultralytics
- add connector coverage: fake-result shims and round-trip tests (N>1, N=1, empty) for the nine previously untested `from_*` connectors and the `detection/tools/transformers.py` processors; one empty-`segments_info` panoptic case is xfail-marked pending a separate fix

* test(ci-fix): drop deprecated Pillow mode arg from panoptic helpers
* test(coverage): add from_qwen_3_vl end-to-end parametrized tests
* test(quality): harden test isolation, xfail strictness, and kwarg forwarding
* fix(detection): fix class_name empty dtype; annotate mask threshold asymmetry
* chore: ruff-format cleanup (blank lines)

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-03 20:09:57 +02:00
Abhijith Neil Abraham afcf13a6f5
fix(annotators): clip BackgroundOverlayAnnotator boxes to the scene… (#2396)
* fix(annotators): clip BackgroundOverlayAnnotator boxes to the scene before   restoring detection regions
* fix(annotators): use explicit np.int32 cast in BackgroundOverlayAnnotator
* test(annotators): strengthen BackgroundOverlayAnnotator test coverage
* docs(changelog): add Unreleased entry for BackgroundOverlayAnnotator fix

---------

Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-03 18:36:25 +02:00
Jirka Borovec 0e1056df19
fix(metrics): count false positives on empty-GT images (#2397)
- Fixed mAP calculation to count predictions on background-only images as false positives
- Fixed all-background mAP inputs to return 0.0 instead of NaN when no ground-truth classes exist
- Updated `from_tensors` documentation to define empty-target background images and their false-positive behavior

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-03 16:17:08 +02:00
Jirka Borovec f173905c8b
fix(dataset): stop split mutation, determinize VOC, guard collisions (#2394)
- `train_test_split` seeded the global `random` module and shuffled the caller's list in place, so `DetectionDataset.split()` reordered its own `image_paths` and polluted process-wide randomness; use a local `random.Random` and shuffle a copy
- Pascal VOC class ids were assigned in `set`-iteration and filesystem-glob order, so the same dataset produced different `class_id` values across runs; sort class names and the loaded file list
- dataset exports keyed output files on basename, silently overwriting when two entries shared a name across directories (common after `merge()`); detect basename collisions and raise
- add regression tests for split determinism, VOC id stability, and export collisions

* fix(dataset): add LabelMe collision guard, hoist pre-flight checks, make guard private
* test(dataset): add collision guard tests for as_yolo, as_pascal_voc, and boundary cases
* docs(dataset): document ValueError raises, fix stale docstrings, add non-mutation guarantee

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-03 15:02:01 +02:00
Jirka Borovec 15dbbb5cb1
fix(annotators): clip crops, fix heatmap wrap, release capture (#2393)
- Fixed annotators to avoid internal deprecation warnings from image overlay usage while preserving the public deprecated wrapper
- Fixed CropAnnotator crashes for partially out-of-frame detections by clipping crops to scene bounds and skipping degenerate boxes
- Fixed HeatMapAnnotator heat disappearing after 256 accumulated frames
- Fixed video frame generation to release the capture when iteration ends early
- Updated documentation for overlay deprecation, crop clipping behavior, and video capture release guarantees

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-03 11:03:45 +02:00
Abhijith Neil Abraham 0d4c3a4fcf
fix(annotators): clip CropAnnotator boxes to the scene before cropping (#2391) 2026-07-03 10:33:49 +02:00
Abhijith Neil Abraham f196e15f26
fix: replace deprecated 2-D np.cross with explicit determinant (#2386)
- Add filterwarnings = ["error::DeprecationWarning"] to pyproject.toml so
  future np.cross 2-D reintroductions fail CI immediately (closes #2384)
- Add test_get_polygon_center_no_deprecation_warning: asserts no
  DeprecationWarning from get_polygon_center (Copilot inline comment)
- Add test_cross_product_no_deprecation_warning: asserts no DeprecationWarning
  from cross_product (Copilot inline comment)
- Add test_cross_product_sign (4 parametrised cases): above / below / on-line /
  offset-start — directly tests the inline determinant correctness
- Improve cross_product docstring: blank line after summary, adds Examples
  section with correct output, notes NumPy 2.0 rationale

---------

Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-02 19:01:39 +02:00