github roboflow/supervision 0.30.9
supervision-0.30.9

5 hours ago

v0.30.9 — Closer to OpenCV without OpenCV

Installs without OpenCV now draw and resize like OpenCV, and the COCO and CreateML loaders stop accepting reversed boxes.

  • BoxAnnotator borders paint the same pixels with or without OpenCV installed.
  • get_video_frames_generator reads browser-recorded WebM and variable frame rate MKV to the end.
  • from_coco, from_pascal_voc and from_createml no longer build boxes with x_min past x_max.
  • get_top_k rejects a negative k instead of dropping one classification.
  • DetectionsSmoother forgets expired tracks on frames without tracker_id.

Drop-in upgrade. Without OpenCV, borders and resized regions shift toward OpenCV's output. Negative k, negative COCO/CreateML box sizes and an epsilon that is NaN, infinite or 1e30 and larger are now rejected; without OpenCV, so is rectangle thickness above 32767.

✨ Spotlights / highlights

NumPy fallback matches OpenCV

Without opencv-python, thick rectangle borders were drawn entirely inside the rectangle. They now extend (thickness + 1) // 2 pixels outside it, like OpenCV. The same release fixes cv2.resize with fx/fy sampling the wrong source pixels (it hit PixelateAnnotator) and approxPolyDP dropping vertices that sit beyond a segment endpoint. For polygons, the fallback now follows OpenCV 4.13 and later; older OpenCV keeps the infinite-line rule, so results differ by installed backend. (#2675, #2690, #2673)

import numpy as np
import supervision as sv

scene = np.zeros((100, 100, 3), dtype=np.uint8)
detections = sv.Detections(xyxy=np.array([[20, 20, 80, 60]]), class_id=np.array([0]))
annotated = sv.BoxAnnotator(thickness=2).annotate(scene, detections)
# before (no OpenCV): 392 painted pixels, border drawn inside the box
# now:                596 painted pixels, same as with OpenCV

Video reads to the end of the stream

With no end, sv.get_video_frames_generator stopped at OpenCV's frame count. A WebM without a duration reports a huge negative count, so browser recordings yielded no frames. It now reads until the stream ends, and sv.process_video without max_frames does the same. (#2672)

for frame in sv.get_video_frames_generator("recording.webm"):
    ...
# before: no frames yielded
# now:    every frame

No more reversed boxes from COCO, Pascal VOC and CreateML

This finishes the from_yolo fix from 0.30.8. COCO and CreateML name an extent, so a negative width or height is rejected. Pascal VOC names two corners, so a reversed pair is ordered. The three exporters order corners first, so a reversed Detections box is written as the same rectangle. (#2683)

A negative k no longer hides a classification

get_top_k(-1) returned every classification except the lowest-confidence one. It now raises. (#2695)

classifications.get_top_k(-1)
# before: all but the lowest-confidence classification
# now:    ValueError: k must be non-negative

Empty and untracked frames behave

InferenceSlicer keeps its oriented-box sequential fallback and warning when the first batch is empty. DetectionsSmoother ages its history on frames without tracker_id, so expired boxes stop affecting a returning track. KeyPoints.from_transformers returns an empty KeyPoints instead of raising IndexError when pose post-processing finds nothing. (#2685, #2676, #2671)

🔄 Migration guide

No migration required for this release. COCO and CreateML annotation files with a negative box width or height now fail to load; correct or remove those boxes.

📝 Notable changes

🌱 Changed

  • sv.DetectionDataset.from_coco and from_createml raise on a negative box width or height; from_pascal_voc orders a reversed corner pair. The three exporters order the corners of a reversed Detections box first and the COCO exporter writes the ordered origin; normal boxes are unchanged. (#2683)
  • sv.Classifications.get_top_k raises ValueError for a negative k; k=0 and k larger than the number of classifications are unchanged. (#2695)
  • Without OpenCV, rectangle thickness must be an integer of at most 32767, as in OpenCV: a non-integer raises TypeError, a larger value ValueError. (#2675)

🔧 Fixed

  • sv.BoxAnnotator, sv.CropAnnotator, sv.PercentageBarAnnotator and sv.draw_rectangle draw a border of thickness 2 or more identically with and without opencv-python. Filled rectangles and thickness=1 borders are unchanged, except zero-height rectangles, which no longer draw 1 or 2 extra pixels. (#2675)
  • The NumPy fallback for cv2.resize maps pixels with fx/fy when dsize is not given, as OpenCV does. sv.PixelateAnnotator could sample the wrong source pixels without OpenCV. (#2690)
  • The NumPy fallback for cv2.approxPolyDP, used by sv.approximate_polygon and YOLO/COCO polygon export, measures distance to the finite segment as OpenCV 4.13+ does, and raises ValueError for a NaN, infinite or 1e30-and-larger epsilon. (#2673)
  • sv.get_video_frames_generator and sv.process_video read to the end of the stream when no end or max_frames is given. A positive frame count still rejects an end past it. (#2672)
  • sv.InferenceSlicer probes past leading empty batches before choosing threaded or sequential execution, so batched callbacks producing oriented boxes keep the sequential fallback and warning. (#2685)
  • sv.DetectionsSmoother ages cached track history on frames without tracker_id; short gaps still preserve smoothing. (#2676)
  • sv.KeyPoints.from_transformers returns an empty KeyPoints when pose post-processing returns no instances for an image. (#2671)

🏆 Contributors

  • Atikul Islam Munna (@atikulmunna, LinkedIn) — centered thick rectangle borders in the NumPy fallback.
  • Mohammad Hijjawi (@MohammadHijjawi97, LinkedIn) — fixed video reading past an unreliable frame count.
  • A Aswanth Raj (@aswanth-07, LinkedIn) — fixed InferenceSlicer empty-batch probing and DetectionsSmoother history aging.
  • Miral Amin (@aminmiral) — made COCO, Pascal VOC and CreateML reject or order reversed boxes.
  • NIKHIL (@Nikhi00718) — rejected negative get_top_k counts and handled empty Transformers pose results.
  • Raashish Aggarwal (@raashish1601) — fixed cv2.resize pixel mapping with fx and fy.
  • kevin (@kevin9327) — fixed approxPolyDP distance measurement in the NumPy fallback.

Automated contributions: @dependabot, @pre-commit-ci


Full changelog: 0.30.8...0.30.9

Don't miss a new supervision release

NewReleases is sending notifications on new releases.