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.
BoxAnnotatorborders paint the same pixels with or without OpenCV installed.get_video_frames_generatorreads browser-recorded WebM and variable frame rate MKV to the end.from_coco,from_pascal_vocandfrom_createmlno longer build boxes withx_minpastx_max.get_top_krejects a negativekinstead of dropping one classification.DetectionsSmootherforgets expired tracks on frames withouttracker_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 OpenCVVideo 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 frameNo 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-negativeEmpty 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_cocoandfrom_createmlraise on a negative box width or height;from_pascal_vocorders a reversed corner pair. The three exporters order the corners of a reversedDetectionsbox first and the COCO exporter writes the ordered origin; normal boxes are unchanged. (#2683)sv.Classifications.get_top_kraisesValueErrorfor a negativek;k=0andklarger than the number of classifications are unchanged. (#2695)- Without OpenCV, rectangle
thicknessmust be an integer of at most 32767, as in OpenCV: a non-integer raisesTypeError, a larger valueValueError. (#2675)
🔧 Fixed
sv.BoxAnnotator,sv.CropAnnotator,sv.PercentageBarAnnotatorandsv.draw_rectangledraw a border ofthickness2 or more identically with and withoutopencv-python. Filled rectangles andthickness=1borders are unchanged, except zero-height rectangles, which no longer draw 1 or 2 extra pixels. (#2675)- The NumPy fallback for
cv2.resizemaps pixels withfx/fywhendsizeis not given, as OpenCV does.sv.PixelateAnnotatorcould sample the wrong source pixels without OpenCV. (#2690) - The NumPy fallback for
cv2.approxPolyDP, used bysv.approximate_polygonand YOLO/COCO polygon export, measures distance to the finite segment as OpenCV 4.13+ does, and raisesValueErrorfor aNaN, infinite or1e30-and-largerepsilon. (#2673) sv.get_video_frames_generatorandsv.process_videoread to the end of the stream when noendormax_framesis given. A positive frame count still rejects anendpast it. (#2672)sv.InferenceSlicerprobes past leading empty batches before choosing threaded or sequential execution, so batched callbacks producing oriented boxes keep the sequential fallback and warning. (#2685)sv.DetectionsSmootherages cached track history on frames withouttracker_id; short gaps still preserve smoothing. (#2676)sv.KeyPoints.from_transformersreturns an emptyKeyPointswhen 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
InferenceSlicerempty-batch probing andDetectionsSmootherhistory aging. - Miral Amin (@aminmiral) — made COCO, Pascal VOC and CreateML reject or order reversed boxes.
- NIKHIL (@Nikhi00718) — rejected negative
get_top_kcounts and handled empty Transformers pose results. - Raashish Aggarwal (@raashish1601) — fixed
cv2.resizepixel mapping withfxandfy. - kevin (@kevin9327) — fixed
approxPolyDPdistance measurement in the NumPy fallback.
Automated contributions: @dependabot, @pre-commit-ci
Full changelog: 0.30.8...0.30.9