Skip to content

releasing 0.30.0 - #2462

Draft
Borda wants to merge 1 commit into
developfrom
releasing/0.30.0
Draft

releasing 0.30.0#2462
Borda wants to merge 1 commit into
developfrom
releasing/0.30.0

Conversation

@Borda

@Borda Borda commented Jul 29, 2026

Copy link
Copy Markdown
Member

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 on opencv-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 for InferenceSlicer, and ships five breaking changes, most notably JSONSink switching to native JSON types and mask_non_max_merge computing 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

import supervision as sv

window = sv.ImageWindow("frame")
for frame in sv.get_video_frames_generator("input.mp4"):
    window.show(frame)
    if window.wait_key(1) == "q":
        break

The largest change in this release: OpenCV stays the default backend when installed, but supervision no longer requires it. sv.ImageWindow replaces cv2.imshow/cv2.waitKey for display. av>=14.2 is now a required dependency for the PyAV video path during this transition.

Soft-NMS

detections = sv.Detections.from_ultralytics(result)
softened = detections.with_soft_nms(sigma=0.5)
filtered = detections.with_soft_nms(sigma=0.5, score_threshold=0.3)

sv.Detections.with_soft_nms (plus sv.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

dataset = sv.DetectionDataset.from_labelme(
    images_directory_path="images/",
    annotations_directory_path="annotations/",
)

import rasterio

with rasterio.open("RGB.byte.tif") as raster:
    slicer = sv.InferenceSlicer(callback=my_model_callback)
    detections = slicer(raster)

DetectionDataset.from_labelme/as_labelme and from_createml/as_createml join the existing COCO/YOLO/Pascal-VOC converters. sv.InferenceSlicer can now read an open rasterio dataset window-by-window for multi-GB aerial/drone GeoTIFFs without loading the whole image (pip install "supervision[geotiff]"), and accepts batch_size for batched-callback inference.

sv.load_image_from_url

image = sv.load_image_from_url("https://media.roboflow.com/notebooks/examples/dog.jpeg")

Load 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.JSONSink now emits native JSON types, not strings:

# before 0.30.0
row["score"] == "0.85"  # str
row["is_valid"] == "True"  # str

# after 0.30.0
row["score"] == 0.85  # float
row["is_valid"] is True  # bool

sv.CSVSink stays textual, but its per-row custom-data slicing now matches JSONSink.

sv.mask_non_max_merge computes exact mask overlap, not a downscaled approximation, and ignores the now-deprecated mask_dimension parameter (removal in 0.33.0). Re-tune your overlap threshold after upgrading. overlap_metric is also now keyword-only — most code goes through Detections.with_nmm(...) and is unaffected, but if you call mask_non_max_merge directly and passed overlap_metric positionally, it is now silently swallowed and reverts to OverlapMetric.IOU (no error, wrong results) — pass overlap_metric=... explicitly.

Detections.merge() on mixed dense + CompactMask inputs now returns a CompactMask, not a plain ndarray:

merged = sv.Detections.merge([dense_detections, compact_mask_detections])
isinstance(merged.mask, np.ndarray)  # was True, now False — it's a CompactMask

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.2 is now a required dependency, and opencv-python is capped <6.

Deprecation removals pushed back one release: ByteTrack, supervision.keypoint, normalized_xyxy, and supervision.dataset.utils RLE compatibility shims — originally scheduled for removal in 0.30.0 — are now scheduled for 0.31.0 instead, giving a full transition window.

📝 Notable changes

🚀 Added

⚠️ Breaking Changes

🌱 Changed

🔧 Fixed


🏆 Contributors

  • Abhijith Neil Abraham (@abhijithneilabraham, LinkedIn) — added KeyPoints.merge(); fixed out-of-bucket metric scoring and key_points edge cases
  • Agis Kounelis (@kounelisagis, LinkedIn) — made get_anchors_coordinates OBB-aware; annotator/perf fixes
  • Andrew Barnes (@Bortlesboat, LinkedIn) — fixed sink state on reopen
  • Dylan Parsons (@dylanparsons, LinkedIn) — converted Detections doctests to runnable examples
  • Erik (@Erol444) — added sv.load_image_from_url
  • HALLOUARD (@YHallouard, LinkedIn) — added Soft-NMS
  • Lee Clement (@leeclemnet, LinkedIn) — fixed COCO export to read image sizes from headers
  • Linas Kondrackis (@LinasKo, LinkedIn) — added batching to InferenceSlicer
  • Madhav-C (@madhavcodez, LinkedIn) — added LabelMe and CreateML dataset formats, GeoTIFF InferenceSlicer support
  • Mahbod (@Ace3Z) — added prefetch to get_video_frames_generator, require_all_anchors to PolygonZone
  • Matt Van Horn (@mvanhorn, LinkedIn) — centralized geometry-aware IoU/area dispatch
  • Murillo Rodrigues (@murillo-ro-silva, LinkedIn) — added show_progress to dataset load/save
  • Nick Herrig (@NickHerrig, LinkedIn) — added the face-blurring cookbook
  • Piotr Skalski (@SkalskiP, LinkedIn) — added Gemini 3.5 Flash VLM support
  • Ruben Haisma (@RubenHaisma, LinkedIn) — perf fixes across mask counting, box IoU, from_tensorflow
  • Saif Khan (@K-saif, LinkedIn) — added the adaptive TP/FP/FN validation mosaic export
  • shao (@shaoming11, LinkedIn) — improved draw/utils.py doctests
  • Shehzad Waseem (@Shehzad3684) — fixed a division-by-zero warning in F1Score
  • Teïlo M (@teilomillet) — fixed the hex parser accepting multiple leading prefixes
  • Vikas saini (@vikassaini77, LinkedIn) — converted fenced examples to doctests; removed defensive asserts in annotators
  • Jirka Borovec (@Borda) — built the cv2-free OpenCV-optional backend (image, geometry, drawing, text, and PyAV video fallback) end to end, plus various hardening fixes across detection, dataset, and metrics modules; release maintainer

Full changelog: 0.29.1...0.30.0

@Borda

Borda commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

Still waiting on #2443

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87%. Comparing base (541b022) to head (fd7c199).

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:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant