0.30.8

roboflow/supervision0.30.8Oct 6, 2026by Borda

Upgrading?

AI Summary

A patch release improving video quality without OpenCV, fixing YOLO pose label parsing, and correcting mAP calculations for class-agnostic scenarios.

Key Highlights

  • `VideoSink` and `process_video` now maintain OpenCV's video bit rate when OpenCV isn't installed.
  • YOLO pose labels are now loaded as boxes instead of polygons.
  • `MeanAveragePrecision` correctly scores class-agnostic runs when only one side has class IDs.
  • Florence-2 detections now return one object per instance, merging split polygons.
  • `from_inference` masks no longer drift up and left due to vertex truncation.

Full Release Notes

# v0.30.8 — Sharper video, cleaner labels

Video, YOLO labels, masks, VLM parsing and mAP all get more accurate.

- **`VideoSink`** keeps OpenCV's video quality when OpenCV isn't installed.
- **`from_yolo`** reads pose labels as boxes instead of polygons.
- **`MeanAveragePrecision`** scores class-agnostic runs right when only one side has class IDs.
- **`from_vlm`** returns one Florence-2 detection per object, not one per polygon.
- **`from_inference`** masks no longer drift up to a pixel up and left.

Drop-in upgrade. Without OpenCV, videos get larger; YOLO labels with a negative width or height now raise `ValueError`.

## ✨ Spotlights / highlights

### `sv.VideoSink` and `sv.process_video` keep quality without OpenCV

The PyAV fallback left the encoder bit rate unset, so `mp4v` and `MJPG` files came out at under half of what `cv2.VideoWriter` writes. It now uses OpenCV's rate settings for every codec except H.264. Files get larger and `vp09` may encode more slowly; `codec="avc1"` keeps files small where an H.264 encoder is available. ([#2661](https://github.com/roboflow/supervision/pull/2661))

```python
import supervision as sv

video_info = sv.VideoInfo.from_video_path("in.mp4")
with sv.VideoSink("out.mp4", video_info) as sink:  # OpenCV not installed
    for frame in sv.get_video_frames_generator("in.mp4"):
        sink.write_frame(frame)
# before: mp4v written at under half OpenCV's bit rate, visibly softer
# now:    same bit rate OpenCV's writer uses
```

### YOLO pose labels load as boxes

A pose row is a box followed by keypoints. `from_yolo` used to parse the whole row as a polygon, giving wrong boxes and masks nobody asked for. It now reads the box and skips the keypoints that `kpt_shape` declares. ([#2655](https://github.com/roboflow/supervision/pull/2655))

```python
ds = sv.DetectionDataset.from_yolo(
    images_directory_path="pose/images",
    annotations_directory_path="pose/labels",
    data_yaml_path="pose/data.yaml",  # kpt_shape: [17, 3]
)
# before: polygon-parsed boxes and masks
# now:    one box per row
```

### Class-agnostic mAP with one-sided class IDs

A perfect match scored zero when only one side carried class IDs, such as SAM proposals checked against labeled ground truth. With `class_agnostic=True`, both sides now count as one class.

### One Florence-2 detection per object (#2648)

Florence-2 returns a segmented object as a list of polygons, one per connected region. An object split in two used to come back as two detections; the polygons now merge into one mask with one box around all of them.

### Roboflow masks sit on the right pixels (#2649)

`from_inference` truncated sub-pixel polygon vertices, shifting each mask up and left by up to a pixel. Vertices are now rounded, the way the COCO, YOLO, LabelMe and Pascal VOC loaders already do.

## 🔄 Migration guide

No migration required for this release.

## 📝 Notable changes

### 🌱 Changed

- `sv.DetectionDataset.from_yolo` raises `ValueError` naming the annotation file when a label has a negative width or height; it used to load a box with `x_min` past `x_max`, which made `Detections.area` negative and skewed IoU and NMS. `as_yolo` now orders the corners of a reversed box before measuring, so it no longer writes a file the loader refuses. (#2663)

### 🔧 Fixed

- `sv.VideoSink` and `sv.process_video` write `mp4v`, `MJPG` and other non-H.264 video at OpenCV's bit rate when OpenCV isn't installed. A frame rate of zero or less now raises `RuntimeError` in `sv.VideoSink`, as it does with OpenCV. (#2661)
- `sv.DetectionDataset.from_yolo` reads the box of Ultralytics pose labels and skips their keypoints; a `kpt_shape` other than `[K, 2]` or `[K, 3]` raises `ValueError`. (#2655)
- `sv.DetectionDataset.from_yolo` names a malformed annotation line, one with too few values or, for OBB, not nine, in a `ValueError` instead of failing on an array shape. (#2665)
- `sv.metrics.MeanAveragePrecision(class_agnostic=True)` treats detections without class IDs as the same class as labeled ones, and unsigned class ID arrays no longer raise `OverflowError` on NumPy 2. (#2650)
- `sv.Detections.from_vlm` with `sv.VLM.FLORENCE_2` merges the polygons of one instance into one detection for `<REFERRING_EXPRESSION_SEGMENTATION>` and `<REGION_TO_SEGMENTATION>`, and skips instances with no usable polygon. (#2648)
- `sv.Detections.from_vlm` with `sv.VLM.QWEN_2_5_VL` or `sv.VLM.QWEN_3_VL` recovers complete detections from a response cut off inside a `bbox_2d` array or right after a complete object. (#2666)
- `sv.Detections.from_inference` rounds polygon vertices to the nearest pixel before rasterising masks, and raises `ValueError` for NaN or infinite vertices. (#2649)
- `sv.xyxy_to_mask` returns an empty mask for a box entirely left of or above the image when its maximum coordinate is a negative fraction. (#2646)
- `sv.Detections.get_anchors_coordinates` computes axis-aligned midpoint anchors without integer overflow. (#2660)
- `sv.LineZone.trigger` ages crossing history on frames whose detections lack `tracker_id`, so a reused track ID no longer creates a false crossing after the track expired. (#2644)
- `sv.LineZoneAnnotator(text_orient_to_line=True)` no longer raises `TypeError` without OpenCV for lines drawn right to left. (#2659)
- The Ultralytics, Inference and YOLO-NAS speed estimation examples measure elapsed time from frame indices; a vehicle missed in one frame of three was reported about 44% too fast. (#2654)
- `examples/speed_estimation/rfdetr_example.py` no longer raises `AttributeError`: `supervision._cv2` now provides `getPerspectiveTransform` and `perspectiveTransform`. (#2652)

## 🏆 Contributors

- **Mohammad Hijjawi** (@MohammadHijjawi97, [LinkedIn](https://www.linkedin.com/in/mohammadhijjawi)) — fixed video quality without OpenCV, Florence-2 instance merging and Roboflow mask rounding.
- **Kari Pikkarainen** (@kari-pikkarainen, [LinkedIn](https://www.linkedin.com/in/karipikkarainen/recent-activity/all/)) — fixed speed estimation timing, the NumPy `flip` fallback and the perspective-transform fallbacks.
- **Miral Amin** (@aminmiral) — made YOLO loading reject negative extents and name malformed lines.
- **NIKHIL** (@Nikhi00718) — fixed `LineZone` history expiry and anchor overflow.
- **kevin** (@kevin9327) — made Qwen parsing recover from cut-off responses.
- **A Aswanth Raj** (@aswanth-07, [LinkedIn](https://www.linkedin.com/in/a-aswanth-raj/)) — fixed class-agnostic mAP.
- **Devulapalli Naga Sri Vaishnavi** (@Vaishnavi220506) — fixed masks for off-frame fractional boxes.
- **JANG BYUNGKUN** (@8rulerstar) — fixed YOLO pose label loading.

*Automated contributions: @dependabot*

______________________________________________________________________

**Full changelog**: <https://github.com/roboflow/supervision/compare/0.30.7...0.30.8>

Related Repositories