`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>
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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
* 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>
- `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>
* 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>
- 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>
- `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>
- 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>
- 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>
- 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>
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>
`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>
`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>
- 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>
- 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>
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>
- 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>
- 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>
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>
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>
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>
* 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>