Commit Graph

5047 Commits

Author SHA1 Message Date
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
pre-commit-ci[bot] 3e80c0ce3c
chore(pre_commit): ⬆ pre_commit autoupdate (#2426)
* chore(pre_commit): ⬆ pre_commit autoupdate

updates:
- [github.com/JoC0de/pre-commit-prettier: fc2da0552b28c24c836d045bfb6c3057b3d11e62 → v3.9.5](fc2da0552b...v3.9.5)
- [github.com/tox-dev/pyproject-fmt: v2.25.1 → v2.25.2](https://github.com/tox-dev/pyproject-fmt/compare/v2.25.1...v2.25.2)
- [github.com/astral-sh/ruff-pre-commit: v0.15.20 → v0.15.21](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.20...v0.15.21)
- [github.com/pre-commit/mirrors-mypy: v2.1.0 → v2.3.0](https://github.com/pre-commit/mirrors-mypy/compare/v2.1.0...v2.3.0)

* Apply suggestions from code review

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>
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
2026-07-14 12:46:15 +02:00
Nick Herrig d5cadf526a
Add cookbook for blurring faces with hosted api (#923)
* Add cookbook for blurring faces with hosted api
* fix: correct Colab URL and spelling errors
* fix: strip outputs and remove GPU section
* fix: improve code quality and notebook structure
* fix: align HTML card and prose style

---------

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: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-11 01:41:49 +02:00
dependabot[bot] 6306b7ca71
⬆️ Bump mistune from 3.2.1 to 3.3.0 in the uv group across 1 directory (#2423)
Bumps the uv group with 1 update in the / directory: [mistune](https://github.com/lepture/mistune).


Updates `mistune` from 3.2.1 to 3.3.0
- [Release notes](https://github.com/lepture/mistune/releases)
- [Changelog](https://github.com/lepture/mistune/blob/main/docs/changes.rst)
- [Commits](https://github.com/lepture/mistune/compare/v3.2.1...v3.3.0)

---
updated-dependencies:
- dependency-name: mistune
  dependency-version: 3.3.0
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-11 00:57:39 +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
dependabot[bot] 39c015c0ff
⬆️ Bump soupsieve from 2.7 to 2.8.4 in the uv group across 1 directory (#2422)
Bumps the uv group with 1 update in the / directory: [soupsieve](https://github.com/facelessuser/soupsieve).


Updates `soupsieve` from 2.7 to 2.8.4
- [Release notes](https://github.com/facelessuser/soupsieve/releases)
- [Commits](https://github.com/facelessuser/soupsieve/compare/2.7...2.8.4)

---
updated-dependencies:
- dependency-name: soupsieve
  dependency-version: 2.8.4
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-11 00:50:36 +02:00
OrbisAI Security 9897b0790f
fix: this dependabot configuration does not set a co... in... (#2419)
Automated security fix generated by OrbisAI Security
2026-07-09 22:05:09 +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 8dedc3474d
chore: update pre-release workflow to support additional tag formats (#2420) 2026-07-09 15:19:43 +02:00
dependabot[bot] 1e4489f61b
⬆️ Bump the uv group across 1 directory with 6 updates (#2417)
Bumps the uv group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [pillow](https://github.com/python-pillow/Pillow) | `11.3.0` | `12.2.0` |
| [requests](https://github.com/psf/requests) | `2.32.5` | `2.33.0` |
| [pytest](https://github.com/pytest-dev/pytest) | `8.4.2` | `9.0.3` |
| [bleach](https://github.com/mozilla/bleach) | `6.2.0` | `6.4.0` |
| [jupyter-server](https://github.com/jupyter-server/jupyter_server) | `2.18.0` | `2.20.0` |
| [urllib3](https://github.com/urllib3/urllib3) | `2.6.3` | `2.7.0` |



Updates `pillow` from 11.3.0 to 12.2.0
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/11.3.0...12.2.0)

Updates `requests` from 2.32.5 to 2.33.0
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.5...v2.33.0)

Updates `pytest` from 8.4.2 to 9.0.3
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.4.2...9.0.3)

Updates `bleach` from 6.2.0 to 6.4.0
- [Changelog](https://github.com/mozilla/bleach/blob/main/CHANGES)
- [Commits](https://github.com/mozilla/bleach/compare/v6.2.0...v6.4.0)

Updates `jupyter-server` from 2.18.0 to 2.20.0
- [Release notes](https://github.com/jupyter-server/jupyter_server/releases)
- [Changelog](https://github.com/jupyter-server/jupyter_server/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jupyter-server/jupyter_server/compare/v2.18.0...v2.20.0)

Updates `urllib3` from 2.6.3 to 2.7.0
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.3...2.7.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-version: 12.2.0
  dependency-type: direct:production
  dependency-group: uv
- dependency-name: requests
  dependency-version: 2.33.0
  dependency-type: direct:production
  dependency-group: uv
- dependency-name: pytest
  dependency-version: 9.0.3
  dependency-type: direct:development
  dependency-group: uv
- dependency-name: bleach
  dependency-version: 6.4.0
  dependency-type: indirect
  dependency-group: uv
- dependency-name: jupyter-server
  dependency-version: 2.20.0
  dependency-type: indirect
  dependency-group: uv
- dependency-name: urllib3
  dependency-version: 2.7.0
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-09 00:51:33 +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
pre-commit-ci[bot] beede8a638
chore(pre_commit): ⬆ pre_commit autoupdate (#2406)
* chore(pre_commit): ⬆ pre_commit autoupdate

updates:
- [github.com/JoC0de/pre-commit-prettier: v3.8.4 → v3.9.4](https://github.com/JoC0de/pre-commit-prettier/compare/v3.8.4...v3.9.4)

* chore(pre_commit): use SHA instead of version tag for pre-commit-prettier

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-06 21:17:27 +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
dependabot[bot] 8fd47a9ec6
⬆️ Bump astral-sh/setup-uv from 8.2.0 to 8.3.0 in the github-actions group (#2405)
Bumps the github-actions group with 1 update: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv).


Updates `astral-sh/setup-uv` from 8.2.0 to 8.3.0
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](fac544c07d...d31148d669)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 8.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 10:35:25 +02:00
dependabot[bot] ced30b48f7
⬆️ Update pydeprecate requirement from <0.10,>=0.9 to >=0.9,<0.11 (#2404)
Updates the requirements on [pydeprecate](https://github.com/Borda/pyDeprecate) to permit the latest version.
- [Release notes](https://github.com/Borda/pyDeprecate/releases)
- [Changelog](https://github.com/Borda/pyDeprecate/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Borda/pyDeprecate/compare/v0.9.0...v0.10.1)

---
updated-dependencies:
- dependency-name: pydeprecate
  dependency-version: 0.10.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 10:34:57 +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
Jirka Borovec 99049d84e1
Fix: resolve major complex review (#2388)
- Fixed in-memory dict-form `DetectionDataset` image access, iteration, equality, and merge behavior, with deprecation messaging retained
- Fixed mAP to honor `metric_target` for mask and oriented-bounding-box evaluation, including correct IoU routing, area handling, crowd semantics, and missing-content errors
- Fixed `ConfusionMatrix.plot()` when plotting raw counts with default normalization disabled
- Improved mask mAP crowd handling performance and memory usage
- Updated the count-in-zone guide to use current APIs

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-02 18:14:04 +02:00
Agis Kounelis 8692148c67
fix(detection): make `get_anchors_coordinates` OBB-aware (#2382)
- Fixed `get_anchors_coordinates` to compute anchor positions from oriented bounding boxes when OBB geometry is available, ensuring anchor-based operations (such as zone counting and annotators) align with the rotated object instead of its axis-aligned bounding box.
- Preserved existing behavior for axis-aligned boxes, while continuing to use mask centroids for `CENTER_OF_MASS` anchors when masks are available.
- Improved the `get_anchors_coordinates` documentation with the updated anchor selection order, OBB usage examples, and notes describing OBB winding-order requirements and anchor tie-breaking behavior.

---------

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-02 00:04:26 +02:00
Ruben 058d8fd990
perf(detection): count mask pixels with `count_nonzero` (#2361)
Mask pixel-area counting used `np.sum` — `np.array([np.sum(m) for m in
masks])` in `Detections.area` and `np.sum(mask, axis=(1, 2))` in the metrics
`get_mask_size_category`. For boolean masks `np.count_nonzero` (with no axis)
dispatches to NumPy's SIMD popcount over the raw byte buffer, whereas every
axis-reduction form — `np.sum(..., axis=...)` and even `np.count_nonzero(...,
axis=...)` — falls back to a slower generic reduction. So counting per mask
with `np.count_nonzero` is several times faster than the "obvious" vectorized
sum, while producing bit-identical integer counts.

Route both sites through `np.fromiter((np.count_nonzero(m) for m in masks),
dtype=np.int64, count=len(masks))`. `dtype=np.int64` preserves the documented
`Detections.area` mask-branch dtype on every platform (a bare
`np.array([...])` of Python ints would be int32 on Windows).

Measured ~5x on 640x640 masks (e.g. `Detections.area`, N=300: ~24ms -> ~4ms),
faster across densities. `get_mask_size_category` feeds the size-bucketed
F1/Precision/Recall/mAP/mAR metrics, where it is invoked repeatedly per
dataset. Counts are integer-exact (verified over 400 randomized trials plus
empty / all-true / all-false / 1x1 edge cases).

Adds parity tests for `Detections.area` (dense mask) and
`get_mask_size_category` against an `np.sum` reference.

---------

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-01 23:22:46 +02:00
Ruben 8f576b02a8
fix(detection): scale `from_tensorflow` boxes by correct axes (#2360)
`Detections.from_tensorflow` scaled the normalized box coordinates by the
wrong image dimensions: the y coordinates (ymin/ymax, columns 0 and 2) were
multiplied by width and the x coordinates (xmin/xmax, columns 1 and 3) by
height. Tensorflow Hub object-detection models emit `detection_boxes` as
normalized `[ymin, xmin, ymax, xmax]`, so y must scale by height and x by
width.

The bug is masked on square images (width == height) but corrupts every
coordinate on the common non-square case — e.g. a box normalized to
`[0.1, 0.2, 0.5, 0.6]` on a 1000x500 image came out as
`[100, 100, 300, 500]` instead of the correct `[200, 50, 600, 250]`.

Swap the two multipliers so y scales by `resolution_wh[1]` (height) and x by
`resolution_wh[0]` (width). Adds a non-square regression test (the connector
was previously untested).

- Expand tensorflow_results arg to document required dict keys and tensor
  shapes so callers know what to pass before getting a KeyError
- Add Note: section documenting the [ymin, xmin, ymax, xmax] normalized
  box format; the inline comment was only visible to code readers
- Fix SOURCE_IMAGE_PATH undefined identifier → "<SOURCE_IMAGE_PATH>"
  string placeholder (consistent with other connector examples in file)

---------

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-01 22:44:01 +02:00
Ruben a32323d5bd
perf(detection): vectorize `box_iou_batch_with_jaccard` (#2359)
`box_iou_batch_with_jaccard` computed COCO-style Jaccard IoU with a double
Python `for` loop calling a scalar `_jaccard` helper once per (detection,
ground-truth) pair — an O(N*M) per-element pattern in otherwise pure-NumPy
code. It is the inner IoU of `COCOEvaluator._compute_iou`, called once per
(image, category) during mAP evaluation, and is also public API
(`sv.box_iou_batch_with_jaccard`).

Replace the loop with a broadcasted NumPy implementation and drop the now
unused scalar `_jaccard`. The far corners are built as `x2 = x + w` and the
union is associated as `(area_det + area_gt - area_inter) + eps` so the
result is bit-identical to the previous per-pair output (verified to
`max|diff| = 0` over 4000 randomized trials including zero/negative-width
degenerate boxes and crowd flags). Crowd semantics are preserved: a crowd
ground truth uses the detection area as the union.

Speedup scales with batch size — ~1.6x at 5x5, ~27x at 15x60, ~66x at
50x100 — and is faster even at the smallest sizes, so there is no regime
where it regresses. End-to-end COCO mAP results are unchanged (the existing
metrics suite passes without modification).

Adds `TestBoxIouBatchWithJaccard`: parity against an independent per-pair
reference across empty / single / busy / degenerate+crowd batches, the crowd
union semantics, the empty-input contract, and the `is_crowd` length guard.

- Improved COCO-style Jaccard IoU batch evaluation performance while preserving existing results, crowd handling, degenerate-box behavior, and public API semantics
- Fixed empty-input returns to preserve the documented `(len(boxes_detection), len(boxes_true))` output shape
- Fixed `is_crowd` length validation to raise a descriptive `ValueError`
- Updated Jaccard IoU documentation to clarify COCO `[x, y, w, h]` input format, output orientation, and NaN propagation

---------

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-01 22:43:26 +02:00
Jirka Borovec d590eb6658
perf(detection): keep mixed-mask Detections.merge compact (#2383)
- Improved `Detections.merge()` to preserve `CompactMask` output when merging dense and compact masks by converting dense masks to compact form, avoiding unnecessary full-mask materialization while keeping all-dense and all-compact behavior unchanged.
- Added validation to mixed-mask merging that raises `ValueError` when compact masks have inconsistent image shapes or dense mask dimensions do not match the compact mask image size.
- Added the public `CompactMask.image_shape` property for safe access to compact mask dimensions.
- Updated `Detections.merge()` documentation to describe mixed-mask merge behavior, output types, validation errors, the lossy dense-to-compact conversion outside detection bounding boxes, and that NMS/NMM pairwise operations do not preserve `CompactMask`.
- Added a comprehensive "Use Compact Masks" how-to guide covering compact mask ingestion, inference, annotator mask requirements, and mixed-mask merging, and integrated it into the documentation navigation.

---------

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: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-01 21:01:29 +02:00
Jirka Borovec 04858a2727
feat: declare annotator mask requirements (#2370)
- Added a `requires_mask` flag to annotators so integrations can determine whether masks must be materialized before annotation.
- Updated mask-only annotators to declare `requires_mask=True`, while mask-optional annotators explicitly declare `requires_mask=False`, including compatibility support for `ComparisonAnnotator`.

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-01 19:34:21 +02:00
Jirka Borovec 3f816c0b6c
perf: avoid compact mask materialization in polygon annotator (#2369)
Use CompactMask crops for polygon extraction and offset crop-local contours back into image coordinates.

Add a regression test covering tight crops, disconnected contours, empty masks, dense parity, and no integer CompactMask indexing.

- Add `_iter_mask_crops()` helper under shared-utilities seam: yields
  (detection_idx, mask_or_crop, offset_or_None) encapsulating the
  CompactMask vs dense isinstance dispatch in one place (eliminates 4th
  inline copy of the same pattern; see _paint_masks_by_area)
- Refactor PolygonAnnotator.annotate() to consume _iter_mask_crops;
  removes the 9-line inline dispatch block
- Add TODO comment at isinstance site flagging MaskLike Protocol as
  follow-up (separate PR; review item #3 self-resolved)
- Extend PolygonAnnotator.annotate() docstring with Note section
  covering CompactMask fast path and offset semantics
- Add N=0 empty CompactMask test (scene unchanged, no error)
- Add all-False mask test (no polygons drawn, documents boundary behavior)
- Add N=1 single-detection parity test (CompactMask == dense)
- Add float xyxy truncation test (sub-pixel xyxy → same output as int xyxy)
- Add disjoint-contour coordinate assertion: both blobs painted at correct
  image-space coords after crop→image offset translation
- Add PolygonAnnotator to TestCompactMaskParity.test_annotator_compact_mask_matches_dense_mask parametrize

---------

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-01 18:05:46 +02:00
Jirka Borovec 3ecd5d0744
Optimize mask annotation ROI blending (#2368)
- Improved MaskAnnotator performance by blending mask overlays only within the affected ROI while preserving dense mask and CompactMask rendering behavior
- Fixed all-false masks to skip unnecessary ROI blending
- Updated compact-mask benchmark output to clarify annotation speedup reporting

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-01 15:55:21 +02:00
Jirka Borovec 098f5315b5
chore: update `uv.lock` to require Python 3.10+ (#2381) 2026-07-01 13:28:01 +02:00
Jirka Borovec beb047095f
feat: add compact RLE mask ingestion (#2367)
- Added compact COCO RLE mask ingestion with a `CompactMask` representation and optional compact mask parsing during inference for substantially lower memory usage on sparse segmentation results.
- Added `Detections.to_compact_masks()` to convert existing dense masks into compact masks while preserving detection and collection metadata.
- Improved compact mask decoding performance with cropped RLE processing, batched decoding on the fast path, vectorized decoding for small images, optimized RLE traversal, and faster delta decoding.
- Improved mask metrics to operate directly on `CompactMask` instances, preserving the compact representation while producing results equivalent to dense masks.
- Fixed mixed-modality inference handling by keeping detections and masks aligned, isolating malformed RLE failures to individual predictions where possible, and falling back safely when decoding cannot be completed.
- Fixed compact mask conversion and parsing to preserve dense-mask pixel content across public parsing and slicing paths, while correctly documenting and applying the intended bbox-cropping behavior for compact COCO RLE masks.
- Improved COCO RLE validation with checks for malformed payloads, invalid dimensions, count overflows, image size limits, count-sum mismatches, bounding-box mismatches, and safe fallback behavior for incompatible mask sizes.
- Added inference benchmarks and documentation demonstrating the memory and inference-time characteristics of compact masks, including guidance on their performance tradeoffs and behavior.

---------

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>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-01 12:50:40 +02:00
Jirka Borovec 4624dde770
fix(metrics): replace np.unique matching with greedy algorithm (#2380)
The two-pass np.unique deduplication in _match_detection_batch dropped
valid TP assignments when a prediction's best-IoU target was already
claimed by a higher-confidence prediction. The greedy one-pass algorithm
(sort by IoU desc, assign if neither target nor pred already matched)
was already used in _split_detections_by_outcome and
ConfusionMatrix.evaluate_detection_batch but missing from Recall,
F1Score, Precision, MeanAverageRecall, and MeanAveragePrecision.

- Fix all five _match_detection_batch implementations
- Add regression tests reproducing the issue #2378 example in each
  affected metric class (IoU matrix [[1.0, 0.667], [0.333, 0.538]])
- Add kind='stable' to np.argsort in _match_detection_batch across all 5 metric
  implementations (Recall, Precision, F1Score, MeanAverageRecall, deprecated
  MeanAveragePrecision) to ensure deterministic TP assignment when IoU values tie
- Add test_greedy_matching_two_valid_pairs to TestDetectionMetrics covering the
  deprecated MeanAveragePrecision._match_detection_batch with the issue #2378 IoU
  matrix, closing the one missing regression test flagged by /review

* refactor(metrics): extract _greedy_match helper to eliminate 5x duplication

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-01 12:30:09 +02:00
Agis Kounelis 97f5c0ca53
perf(annotators): skip corner circles when drawing square label backgrounds (#2346)
Both rounded-rectangle helpers (LabelAnnotator.draw_rounded_rectangle and the
public draw_rounded_rectangle in draw/utils) always drew two rectangles plus
four corner circles, even when border_radius is 0, which is the default for
LabelAnnotator and VertexLabelAnnotator. With a zero radius that is six cv2
calls per label per frame (the four circles are zero-radius no-ops) where one
fill rectangle does the same thing.

Add a square-corner fast path to both helpers. Output is pixel identical; only
the redundant calls go away. On a 1080p frame with 100 labels LabelAnnotator
drops from ~2.1 ms to ~1.3 ms (about 1.6x), and the rounded-rectangle call
itself is ~2.8x faster at radius 0. The radius > 0 path is unchanged.

Adds tests pinning square output to a plain rectangle for both helpers (the
public draw/utils function had no tests before).

- Rename LabelAnnotator.draw_rounded_rectangle to _draw_rounded_rectangle
  (accidentally public static method — now signals internal)
- Expand draw/utils.py border_radius docstring: document <= 0 and
  clamp-to-zero fast-path behaviour
- Add crash-era comment to both test files: border_radius < 0 previously
  raised cv2.error; fast path silently draws square corners instead
- Add clamped-to-zero test in both test files: positive radius on a
  1px-wide box clamps to 0 and triggers the fast path
- Strengthen positive-radius assertion: full center-row check + all four
  corners unpainted (replaces two-pixel spot check)
- Add pytest.param(id=) slugs to all parametrize decorators per
  CONTRIBUTING.md convention
- Add Google-style docstring with Args, Returns, Example to
  `LabelAnnotator.draw_rounded_rectangle` (was undocumented @staticmethod)
- Rename `testdraw_*` → `test_draw_*` in `TestLabelAnnotator` to restore
  consistent test naming broken by the earlier private-rename commit
- Expand `draw/utils.draw_rounded_rectangle` border_radius docstring:
  note that negative values previously raised `cv2.error` and now draw
  square corners silently; drop "as a fast path" implementation detail
- Add `Example:` block to `draw/utils.draw_rounded_rectangle`

---------

Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-07-01 01:25:25 +02:00
Agis Kounelis e1b7a16101
fix(detection): keep `from_inference` aligned on partial masks (#2362)
process_roboflow_result appended a mask only for predictions carrying one
(RLE or polygon), while xyxy/confidence/class_id were appended for every
prediction. A result mixing masked and box-only predictions (e.g. a
segmentation batch where one polygon is empty) produced a mask array shorter
than the boxes, so Detections.from_inference raised a shape-mismatch error.

Append None for box-only predictions and build the mask array only when every
prediction has a mask, otherwise drop masks to preserve alignment, mirroring
the tracker_id handling. Fully-masked and mask-free results are unchanged.

- Update `masks` Returns clause to document partial-drop case and corrupt-RLE blast radius (D1+C1)
- Remove stale "known limitation" note from from_inference docstring; describe actual behavior (D2)
- Extract _all_present_or_none() helper; eliminate duplicated partial-drop-warn pattern (S1)

---------

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-01 00:52:57 +02:00
pre-commit-ci[bot] 15f56dea30
chore(pre_commit): ⬆ pre_commit autoupdate (#2375)
* chore(pre_commit): ⬆ pre_commit autoupdate

updates:
- [github.com/JoC0de/pre-commit-prettier: v3.8.4 → v3.9.3](https://github.com/JoC0de/pre-commit-prettier/compare/v3.8.4...v3.9.3)
- [github.com/tox-dev/pyproject-fmt: v2.25.0 → v2.25.1](https://github.com/tox-dev/pyproject-fmt/compare/v2.25.0...v2.25.1)
- [github.com/astral-sh/ruff-pre-commit: v0.15.18 → v0.15.20](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.18...v0.15.20)

* fix(pre_commit): 🎨 auto format pre-commit hooks
* fix(pyproject): restore valid mypy TOML overrides
* chore: update pyproject.toml to exclude examples and tests in mypy configuration

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jirka <6035284+Borda@users.noreply.github.com>
2026-06-30 23:02:13 +02:00
Jirka Borovec 934da124f5
chore(typing): Add explicit selection helpers (#2373)
* Add explicit selection helpers
* improve typing in detection metrics and update pre-commit dependencies

- Add explicit type annotation for `panel_array` in `_draw_panel` function.
- Update `.pre-commit-config.yaml` to include `tomli>=2.0.1` as an additional dependency for `pyproject-fmt`.

---------

Co-authored-by: Codex <codex@openai.com>
2026-06-29 15:39:58 +02:00
pre-commit-ci[bot] ad2c75021f
chore(pre_commit): ⬆ pre_commit autoupdate (#2248)
* chore(pre_commit): ⬆ pre_commit autoupdate

updates:
- [github.com/JoC0de/pre-commit-prettier: v3.8.3 → v3.8.4](https://github.com/JoC0de/pre-commit-prettier/compare/v3.8.3...v3.8.4)
- [github.com/tox-dev/pyproject-fmt: v2.21.1 → v2.25.0](https://github.com/tox-dev/pyproject-fmt/compare/v2.21.1...v2.25.0)
- [github.com/astral-sh/ruff-pre-commit: v0.15.12 → v0.15.18](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.12...v0.15.18)
- [github.com/pre-commit/mirrors-mypy: v1.20.2 → v2.1.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.20.2...v2.1.0)

---------

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>
2026-06-29 14:52:18 +02:00