releasing 0.30.0 - #2462
Draft
Borda wants to merge 1 commit into
Draft
Conversation
Member
Author
|
Still waiting on #2443 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #2462 +/- ##
=======================================
Coverage 87% 87%
=======================================
Files 85 85
Lines 12021 12021
=======================================
Hits 10424 10424
Misses 1597 1597 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0.30.0: Run supervision without OpenCV
📋 Summary
supervision 0.30.0 makes OpenCV optional. A new private
_cv2/backend (NumPy and Pillow, with PyAV for the video path) reimplements every OpenCV call the library needs, so supervision now runs onopencv-python-headless— or no OpenCV wheel at all — instead of crashing on import. This release also adds Soft-NMS, LabelMe and CreateML dataset formats, GeoTIFF-aware windowed reads forInferenceSlicer, and ships five breaking changes, most notablyJSONSinkswitching to native JSON types andmask_non_max_mergecomputing exact mask overlap instead of a downscaled approximation. Python 3.9 support is dropped — 3.10 is now the minimum.✨ Spotlights / highlights
Run supervision without OpenCV
The largest change in this release: OpenCV stays the default backend when installed, but supervision no longer requires it.
sv.ImageWindowreplacescv2.imshow/cv2.waitKeyfor display.av>=14.2is now a required dependency for the PyAV video path during this transition.Soft-NMS
sv.Detections.with_soft_nms(plussv.box_soft_non_max_suppression/sv.mask_soft_non_max_suppression) rescales overlapping detections' confidence instead of discarding them outright — useful in crowded scenes where hard NMS drops valid overlapping objects.New dataset formats + GeoTIFF-aware slicing
DetectionDataset.from_labelme/as_labelmeandfrom_createml/as_createmljoin the existing COCO/YOLO/Pascal-VOC converters.sv.InferenceSlicercan now read an openrasteriodataset window-by-window for multi-GB aerial/drone GeoTIFFs without loading the whole image (pip install "supervision[geotiff]"), and acceptsbatch_sizefor batched-callback inference.sv.load_image_from_urlLoad an image straight from an HTTP(S) URL as an OpenCV array, with optional on-disk caching.
🔄 Migration guide
Five breaking changes. Most require no code changes beyond a type check or threshold recalibration.
sv.JSONSinknow emits native JSON types, not strings:sv.CSVSinkstays textual, but its per-row custom-data slicing now matchesJSONSink.sv.mask_non_max_mergecomputes exact mask overlap, not a downscaled approximation, and ignores the now-deprecatedmask_dimensionparameter (removal in0.33.0). Re-tune your overlap threshold after upgrading.overlap_metricis also now keyword-only — most code goes throughDetections.with_nmm(...)and is unaffected, but if you callmask_non_max_mergedirectly and passedoverlap_metricpositionally, it is now silently swallowed and reverts toOverlapMetric.IOU(no error, wrong results) — passoverlap_metric=...explicitly.Detections.merge()on mixed dense +CompactMaskinputs now returns aCompactMask, not a plainndarray:The all-dense merge path is unchanged. This is also ~2500× less peak memory and ~13× faster on a 1080p frame with 40 detections.
Python 3.10+ is now required — 3.9 reached end-of-life in October 2025.
av>=14.2is now a required dependency, andopencv-pythonis capped<6.Deprecation removals pushed back one release:
ByteTrack,supervision.keypoint,normalized_xyxy, andsupervision.dataset.utilsRLE compatibility shims — originally scheduled for removal in0.30.0— are now scheduled for0.31.0instead, giving a full transition window.📝 Notable changes
🚀 Added
sv.load_image_from_url— load an HTTP(S) image as an OpenCV array, with optional on-disk caching (feat: add image URL loader #2372)_cv2backend facade — image/geometry/drawing/text/video without OpenCV (refactor(cv2): add optional backend facade #2430, feat(cv2): add image fallback backend #2431, feat(cv2): add geometry fallbacks #2432, feat(cv2): add drawing fallbacks #2433, feat(cv2): add Hershey text fallback #2435, feat(video): require PyAV during cv2 transition #2438, feat(cv2): complete fallback integration #2439, refactor(cv2): replace Hershey text with Pillow #2440)sv.ImageWindow— tkinter+Pillow desktop window replacingcv2.imshow/cv2.waitKey(feat(utils): addTkImageWindowto unblock switch toopencv-python-headless#2320)sv.box_soft_non_max_suppression,sv.mask_soft_non_max_suppression,sv.Detections.with_soft_nms(feat: Add soft Non-Max suppression #1624)sv.VLM.GOOGLE_GEMINI_3_5—Detections.from_vlmparses Gemini 3.5 output (feat(vlm): add Gemini 3.5 Flash parsing support #2449)get_video_frames_generator(prefetch=...)— background-thread decode into a bounded queue (feat(utils): add prefetch toget_video_frames_generator#2273)PolygonZone(require_all_anchors=...)— toggle all-anchors vs. any-anchor containment (feat(detection): add require_all_anchors to PolygonZone #2272)KeyPoints.merge()— combine a list ofKeyPoints, mirroringDetections.merge(feature: add KeyPoints.merge() method #2412)BaseAnnotator.requires_mask— class-level flag on all annotators (feat: declare annotator mask requirements #2370)CompactMask.from_coco_rle+Detections.from_inference(compact_masks=True)(feat: add compact RLE mask ingestion #2367)CompactMask.image_shapeproperty (perf(detection): keep mixed-mask Detections.merge compact #2383)sv.mask_to_roi— exclusive mask-bound helper for slicing/crops (fix: remaining review findings in dataset, docs, and tests #2416)DetectionDataset.from_labelme/as_labelme(feat(dataset): add LabelMe format support to DetectionDataset #2299)DetectionDataset.from_createml/as_createml(feat(dataset): add CreateML format support to DetectionDataset #2284)InferenceSlicerGeoTIFF support —sv.WindowedRasterDataset,pip install "supervision[geotiff]"(feat(detection): support windowed GeoTIFF reads in InferenceSlicer #2281)InferenceSlicer(batch_size=...)— batched callback contract (Inference slicer batching #1239)show_progress: bool = Falseon allDetectionDatasetload/save methods (feat: add show_progress to dataset load/save operations #2275)ConfusionMatrix.benchmark(save_directory_path=...)— adaptive TP/FP/FN validation-mosaic export (Add adaptive TP/FP/FN validation mosaic export #2271)HeatMapAnnotator.reset(),TraceAnnotator.reset(),DetectionsSmoother.reset()— clear accumulated per-stream state (fix(annotators): clip crops, fix heatmap wrap, release capture #2393, fix: close out remaining review findings #2418)AREA_DATA_FIELDconfig constant ( fix(metrics): ignore out-of-bucket detections in size-bucketed sco… #2428)sv.denormalize_boxesandsv.xyxyxyxy_to_xyxynow exported at the top leveluv.lockto require Python 3.10+ #2381)av>=14.2required;opencv-pythoncapped<6(feat(video): require PyAV during cv2 transition #2438, ⬆️ Update opencv-python requirement from <5,>=4.5.5.64 to >=4.5.5.64,<6 #2444)sv.JSONSinkemits native JSON types instead of strings;sv.CSVSinkcustom-data slicing now matchesJSONSink(Fix detection medium review findings #2400)sv.mask_non_max_mergecomputes exact overlap, ignoresmask_dimension(Fix detection medium review findings #2400)Detections.merge()on mixed dense +CompactMaskinputs returnsCompactMask(perf(detection): keep mixed-mask Detections.merge compact #2383)🌱 Changed
DetectionDataset/ClassificationDatasetequality now compares orderedclasseslists, not an unordered set (Fix: resolve major complex review #2388, fix: resolve medium dataset findings #2408)ByteTrack,supervision.keypoint,normalized_xyxy, dataset-utils RLE compat removals moved0.30.0→0.31.0(fix(docs): resolve review deprecation follow-ups #2415)count_nonzeromask pixel counts (perf(detection): count mask pixels withcount_nonzero#2361), vectorizedbox_iou_batch_with_jaccard(perf(detection): vectorizebox_iou_batch_with_jaccard#2359), faster mask-annotation ROI blending (Optimize mask annotation ROI blending #2368), fewer corner circles on square label backgrounds (perf(annotators): skip corner circles when drawing square label backgrounds #2346), less compact-mask materialization in the polygon annotator (perf: avoid compact mask materialization in polygon annotator #2369)🔧 Fixed
import supervisionno longer surfaces the deprecatedByteTrackwarningsv.CSVSink/sv.JSONSinkstarts a fresh session — no stale rows or header (Fix sink state when instances are reopened #2459)from_vlmGemini 2.0/2.5/3.5 salvages valid entries from partially malformed JSON arrays (feat(vlm): add Gemini 3.5 Flash parsing support #2449)save_coco_annotations/as_cocoread image sizes from headers, no pixel decode for labels-only export (fix: read COCO export image sizes from headers instead of decoding pixels #2442)sv.F1Scoreno longer emits a spurious div-by-zeroRuntimeWarning(fix(metrics): avoid division by zero RuntimeWarning in F1Score using np.divide #2437)Precision/Recall/F1Scoreno longer miscount out-of-bucket detections ( fix(metrics): ignore out-of-bucket detections in size-bucketed sco… #2428, fix: resolve medium dataset findings #2408)sv.box_iou_batchupcasts corners tofloat64, fixing int-dtype overflow (fix: close out remaining review findings #2418)from_tensorflowscales boxes by correct axes (fix(detection): scalefrom_tensorflowboxes by correct axes #2360);from_inferencestays aligned on partial masks (fix(detection): keepfrom_inferencealigned on partial masks #2362) and partialtracker_id(fix(detection): do not crashfrom_inferenceon partialtracker_id#2353)get_anchors_coordinatesis OBB-aware (fix(detection): makeget_anchors_coordinatesOBB-aware #2382)CropAnnotator( fix(annotators): clip CropAnnotator boxes to the scene before cropping #2391),HeatMapAnnotatoruint8 wrap (fix(annotators): clip crops, fix heatmap wrap, release capture #2393),BackgroundOverlayAnnotatornegative coords ( fix(annotators): clip BackgroundOverlayAnnotator boxes to the scene… #2396);get_video_frames_generatorreleases capture via try/finally (fix(annotators): clip crops, fix heatmap wrap, release capture #2393)ByteTrackno longer mutates inputDetections; hardened edge cases (fix(tracker): harden ByteTrack edge cases #2413)KeyPoints.as_detectionsaccepts numpy/tuple/generator indices (fix(key_points): handle empty and numpy index input, keep degenerate skeletons #2402)hex_to_rgbarejects multiple leading#(Fix hex parser accepting multiple leading prefixes #2421);Color(...)validates RGBA range (fix(annotators): resolve annotator medium findings #2407)ConfusionMatrixrejects invalid class ids, per-class recall per max-det cutoff, userignoreflags preserved (fix(metrics): harden scoring edge cases #2411); FP counted on empty-GT images (fix(metrics): count false positives on empty-GT images #2397)Classifications.from_timmsoftmaxes logits;download_assetsverifies MD5 + retries once (fix(utils): normalize timm confidences and verify assets #2414)ColorPalette.by_idx()on empty palette raisesValueErrornotZeroDivisionError(fix(annotators): resolve annotator medium findings #2407)ImageSink.save_image()raisesOSErroron cv2 write failure (fix: remaining review findings in dataset, docs, and tests #2416)np.crosswith explicit determinant ( fix: replace deprecated 2-D np.cross with explicit determinant #2386); removed defensive asserts in image annotators (Refactor/remove asserts annotators image #2354)🏆 Contributors
KeyPoints.merge(); fixed out-of-bucket metric scoring andkey_pointsedge casesget_anchors_coordinatesOBB-aware; annotator/perf fixesDetectionsdoctests to runnable examplessv.load_image_from_urlInferenceSlicerInferenceSlicersupportprefetchtoget_video_frames_generator,require_all_anchorstoPolygonZoneshow_progressto dataset load/savefrom_tensorflowdraw/utils.pydoctestsF1ScoreFull changelog: 0.29.1...0.30.0