0.30.6
triggerdotdev/trigger.dev0.30.6Sep 29, 2026by Borda
Upgrading?
AI Summary
supervision 0.30.6 fixes critical bugs in image conversion, dataset export, and counting logic, including a major rewrite of `pillow_to_cv2` to handle various image modes correctly and fixes for line crossing detection and dataset splitting validation.
Key Highlights
- Major fix for `pillow_to_cv2` handling 1-bit masks, 16-bit depth maps, and CMYK images
- `LineZone.trigger` no longer inflates counts with unconfirmed tracks
- `DetectionDataset` exports now correctly handle box-only objects in mixed datasets
- `split` methods now raise errors for invalid ratios instead of silently misbehaving
New Features
- Dataset splits now validate ratios and raise errors for invalid inputs
- DetectionDataset exporters now include box-only objects in mixed datasets
- DetectionsSmoother no longer crashes on objects seen on different frames
Full Release Notes
# 0.30.6: Pillow-conversion, dataset-export, and line-crossing correctness fixes
supervision 0.30.6 is a patch release closing 12 library correctness bugs and landing 2 behavior refinements across datasets, annotators, key points, line-crossing counting, and the Pillow-based fallback backend, plus a new docs guide and a notebook dead-link fix. No new public API, no breaking changes. The broadest-reach fix rewrites `pillow_to_cv2`, the entry point every annotator except `RichLabelAnnotator` and several image helpers use to convert a Pillow image: it used to pass raw mode bytes straight through, so a 1-bit mask, a 16-bit depth map, an `LA`/`PA` image, or a CMYK JPEG all drew wrong or crashed. Two fixes close silent-wrong-data bugs rather than crashes: `LineZone.trigger` let unconfirmed tracks inflate crossing counts, and `DetectionDataset.as_yolo`/`.as_pascal_voc` silently dropped box-only objects from a mixed polygon/box COCO dataset. `DetectionsSmoother` no longer crashes when two tracked objects first seen on different frames carry different metadata (e.g. RF-DETR's `source_image`); its own docstring pipeline was broken. Every library fix ships a regression test.
## β¨ Spotlights / highlights
### `sv.pillow_to_cv2` now converts every Pillow mode the way `cv2.imread` would
Raw mode bytes used to pass straight through: a 1-bit mask came back as `0`/`1` instead of `0`/`255`, a 16-bit depth map wrapped modulo 256 and drew as noise, an `LA`/`PA` image crashed in `cvtColor` on its 2-channel array, and a CMYK JPEG drew its cyan/magenta/yellow ink as red/green/blue. This function is the entry point for every annotator except `RichLabelAnnotator` (which stays on the Pillow path) plus `crop_image`, `resize_image`, `letterbox_image`, `scale_image`, `tint_image`, `grayscale_image`, and `plot_image` whenever handed a Pillow image, so the bug reached the whole drawing surface, not just one call site. A single-channel grayscale image also drew from a read-only buffer view before this fix. Annotating into it silently failed; it now hands back a writable copy.
```python
from PIL import Image
depth_map = Image.open("depth.tif") # mode "I;16"
scene = sv.pillow_to_cv2(depth_map)
# clipped to the 16-bit range and keeps its high byte, instead of wrapping mod 256
```
RGB, RGBA, grayscale, and palette images are unchanged.
### `sv.LineZone.trigger` no longer lets unconfirmed tracks inflate counts
Detections with a negative `tracker_id` (how trackers like `ByteTrackTracker` mark an unconfirmed track) all keyed under one shared id. Two distinct unconfirmed objects crossing on opposite sides in the same frame read as one track oscillating, silently inflating `in_count`/`out_count` with crossings no confirmed track ever made. Confirmed tracks (`tracker_id >= 0`) are counted exactly as before.
### `sv.DetectionDataset.as_yolo` / `.as_pascal_voc` stop dropping box-only objects
`from_coco` gives an all-zero mask to any annotation without its own `segmentation` when a sibling annotation has one, and to every annotation when `force_masks=True`. The exporters only ever wrote the polygon traced from a mask, so a mixed polygon/box COCO dataset silently lost its box-only objects on export, and a box-only COCO dataset loaded with `force_masks=True` wrote empty YOLO label files or object-less Pascal VOC files. A detection with an empty or contour-less mask now exports as its bounding box instead.
### `sv.DetectionsSmoother` no longer crashes on a second tracked object
Each smoothed track was built on the oldest frame in its window, so two objects first seen on different frames carried different frames' `metadata` (exactly what the RF-DETR / `inference` connectors attach), and `Detections.merge` rejected the mismatch. `class_id` and `data` (e.g. `class_name`) now follow the current frame instead of lagging up to `length - 1` frames behind a class change; `xyxy`, `confidence`, and oriented-box corners are still averaged as before.
### Dataset splits reject an out-of-range ratio instead of silently mis-splitting
`sv.DetectionDataset.split`, `sv.ClassificationDataset.split` (both take `split_ratio`), and the internal `train_test_split` helper they call (takes `train_ratio`) never validated the ratio. A finite out-of-range value looked like a successful split: for 10 images, a ratio of `-0.2` returned 8/2 via negative slicing, and `1.2` (or an accidental percentage like `80`) returned 10/0 with no held-out data, no error either way.
```python
train, test = dataset.split(split_ratio=80) # meant 80%
# now raises ValueError naming the problem, instead of silently returning
# every image as train and none as test
```
`0` and `1` keep their existing meanings. Not an API break: no signature changed, only previously-silent input now raises.
## π Migration guide
No breaking changes in this release.
No deprecations or removals landed in 0.30.6 either. All scheduled `remove_in` markers in the codebase target `0.31.0` or `0.32.0` and are untouched by this patch release.
Two entries change *output values* rather than only fixing a crash or a silently-wrong count; not API breaks, but worth checking if your code depends on the old values:
- `sv.KeyPoints.from_ultralytics` / `.from_inference` / `.from_detectron2`: `as_detections().confidence` now carries the model's own detection score, not the mean of the per-keypoint confidences.
- `sv.DetectionsSmoother`: `class_id` and `data` fields on a smoothed track now follow the current frame instead of lagging behind a class change.
## π Notable changes
### π§ Fixed
**Annotators / key points**
- `sv.VertexEllipseHaloAnnotator` now draws the whole halo of a key point whose covariance ellipse is not horizontal. A vertical or diagonal ellipse used to be clipped to a thin band because the fade box was sized as if the major axis always ran along the image x axis. Horizontal ellipses are drawn exactly as before. ([#2634](https://github.com/roboflow/supervision/pull/2634))
- `sv.KeyPoints.from_ultralytics`, `.from_inference` and `.from_detectron2` now keep each object's detection score as `detection_confidence` instead of dropping it, which previously made `sv.KeyPoints.with_nms` raise `ValueError` and `as_detections()` report the mean keypoint confidence instead of the model's own score. ([#2633](https://github.com/roboflow/supervision/pull/2633))
- `sv.LabelAnnotator` now sizes the label background correctly for a label containing a blank line. Text drew each blank line at full height while the background measured it as zero, pushing the last line outside the box. Labels without blank lines are unchanged. ([#2632](https://github.com/roboflow/supervision/pull/2632))
- `sv.IconAnnotator` now draws a palette icon that carries its own alpha channel (Pillow `PA` mode, storable in TIFF) instead of raising `ValueError`. Palettes without alpha, and every read with OpenCV installed, are unchanged. ([#2624](https://github.com/roboflow/supervision/pull/2624))
**Datasets**
- `sv.DetectionDataset.as_yolo` / `.as_pascal_voc` now write a detection whose mask is empty or has no valid contour as its bounding box instead of silently leaving it out of the label file. ([#2631](https://github.com/roboflow/supervision/pull/2631))
- `sv.DetectionDataset.from_yolo` now loads a label row carrying a trailing confidence or tracker id (written by Ultralytics `save_txt` with `save_conf=True` or tracking on) instead of raising `ValueError`, for both box and segmentation rows. The extra token is ignored; box and polygon geometry are unchanged. An odd-length polygon row with no extra field now loses its last value rather than raising, since coordinate parity is the only signal separating the two cases. ([#2619](https://github.com/roboflow/supervision/pull/2619), [#2626](https://github.com/roboflow/supervision/pull/2626), [#2635](https://github.com/roboflow/supervision/pull/2635))
**Tracking**
- `sv.DetectionsSmoother` no longer raises `ValueError: Conflicting metadata` when a second tracked object, first seen on a different frame, enters the smoothing window. ([#2628](https://github.com/roboflow/supervision/pull/2628))
- `sv.LineZone.trigger` now ignores detections with a negative `tracker_id` (the value trackers such as `ByteTrackTracker` report for an unconfirmed track) instead of letting them silently inflate `in_count`/`out_count`. ([#2623](https://github.com/roboflow/supervision/pull/2623))
**Detection utils**
- `sv.polygon_to_mask` now accepts a list/tuple/array-like of `[x, y]` vertices (not just a NumPy array) and returns an all-zero mask for an empty or under-3-vertex polygon instead of crashing inside OpenCV/NumPy with an opaque error. A malformed polygon now raises `ValueError` naming the problem. ([#2622](https://github.com/roboflow/supervision/pull/2622))
- `sv.Detections.from_sam3` now keeps SAM 3 PVS contour fragments with fewer than 3 vertices instead of dropping them. Single points and 2-point edges are rasterized directly into the mask and bounding box. ([#2625](https://github.com/roboflow/supervision/pull/2625))
**Image / IO**
- `sv.pillow_to_cv2` now converts every Pillow mode to the 8-bit array `cv2.imread` would produce, reaching every annotator plus `crop_image`, `resize_image`, `letterbox_image`, `scale_image`, `tint_image`, `grayscale_image`, and `plot_image`. ([#2614](https://github.com/roboflow/supervision/pull/2614))
- `sv.CSVSink` now writes UTF-8 on every platform, preserving non-English detection labels and custom fields on Windows. ([#2615](https://github.com/roboflow/supervision/pull/2615))
**Docs**
- Dead documentation links fixed across the published notebooks (`quickstart.ipynb`, `annotate-video-with-detections.ipynb`, `underestand-visitors-with-yolo-world.ipynb`). ([#2630](https://github.com/roboflow/supervision/pull/2630))
### π± Changed
- `sv.DetectionDataset.split`, `sv.ClassificationDataset.split`, and the internal `train_test_split` helper they call now reject a ratio outside `[0, 1]` (`NaN` and `Β±inf` included) with a `ValueError` naming the problem, instead of silently mis-splitting or dropping the held-out set. ([#2611](https://github.com/roboflow/supervision/pull/2611))
- `sv.tint_image` and `sv.grayscale_image` now accept a single-channel `(H, W)` array or grayscale `Image`, as `sv.letterbox_image` already did. ([#2614](https://github.com/roboflow/supervision/pull/2614))
- New docs guide: "Evaluate targets from a PyTorch DataLoader" in `docs/metrics/mean_average_precision.md`, cross-linked from `docs/how_to/benchmark_a_model.md`. `Detections.from_transformers` gained a docstring note that it expects post-processed predictions, not raw DataLoader targets. ([#2620](https://github.com/roboflow/supervision/pull/2620))
## π Contributors
- **Mohammad Hijjawi** (@MohammadHijjawi97, [LinkedIn](https://www.linkedin.com/in/mohammadhijjawi)) β the `DetectionsSmoother` conflicting-metadata crash, the `KeyPoints` detection-score fix, the YOLO/Pascal VOC empty-mask export fix, the `VertexEllipseHaloAnnotator` rotated-ellipse fix, the `LabelAnnotator` blank-line background fix, and the `polygon_to_mask` crash fix
- **Raghav Rathi** (@raghav-rathi, [LinkedIn](https://www.linkedin.com/in/raghavrathi00/)) β the `pillow_to_cv2` rewrite for every Pillow mode
- **Zachary Alexander** (@zachsplat) β the `LineZone` unconfirmed-track fix
- **NIKHIL** (@Nikhi00718) β the YOLO segmentation-label trailing-value fix
- **Manoj Kumar Thapa** (@iammanoj807, [LinkedIn](https://www.linkedin.com/in/manoj-kumar-thapa-7595a5168)) β the palette-with-alpha `IconAnnotator` fix
- **kevin** (@kevin9327) β the YOLO box-label trailing-value fix
- **Andrew Barnes** (@Bortlesboat, [LinkedIn](https://www.linkedin.com/in/andrew-barnes-705a08195/)) β the CSV Unicode export fix
- **4rch1e** (@archie0732) β the dataset split-ratio validation
- **Salman Ansari** (@salmanwnl44, [LinkedIn](https://www.linkedin.com/in/salmanwnl/)) β the PyTorch DataLoader-targets docs guide
- **Pratik Gandhi** (@pratikgx, [LinkedIn](https://www.linkedin.com/in/pratikgandhix)) β dead-link fixes in the published notebooks
- **Jirka Borovec** (@Borda, [LinkedIn](https://linkedin.com/in/jirka-borovec)) β the `from_sam3` degenerate-fragment fix
______________________________________________________________________
**Full changelog**: https://github.com/roboflow/supervision/compare/0.30.5...0.30.6
Related Repositories
openclaw/openclawβ
392,689
The AI that really does things. Any OS. Any Platform. The lobster way. π¦
nilbuild/developer-roadmapβ
370,064
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
morluto/reaβ
357,450
Reverse engineer anything with agents, from app behavior down to native binaries.
anomalyco/opencodeβ
219,652
The open source coding agent.
n8n-io/n8nβ
208,248
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.