Repository navigation
releasing 0.31.0 [squash & merge] - #2742
Conversation
a2a4607 to
4ee7f81
Compare
There was a problem hiding this comment.
🟢 Approval recommended
The changes are limited to consistent release metadata and documentation, with no unresolved blocking findings.
0 open findings
What changed in this PR
🟢 Approve — prepares Supervision 0.31.0 for release through version metadata and documentation updates, without changing library runtime logic.
Changes:
- Finalizes the package version and release changelog.
- Corrects RF-DETR examples for color order, video annotation, and benchmarking.
- Documents Gemini formats, MediaPipe support, and compact-mask cropping.
No actionable issues remain. Coverage includes release consistency, examples, and documentation accuracy; tests were not rerun.
Quality: code 5/5 (focused changes), testing 3/5 (execution unverified), documentation 5/5 (clearer guidance). Overall risk: 1/5.
| File | Description |
|---|---|
uv.lock |
Updates lock revision and release version. |
src/supervision/utils/video.py |
Corrects the RF-DETR video callback example. |
src/supervision/key_points/core.py |
Adds RGB conversion to RF-DETR examples. |
src/supervision/detection/tools/inference_slicer.py |
Corrects tile color order in the example. |
src/supervision/detection/core.py |
Adds a Gemini structured-output example. |
pyproject.toml |
Sets version to 0.31.0. |
docs/how_to/use_compact_masks.md |
Clarifies cropping by mask encoding. |
docs/how_to/benchmark_a_model.md |
Retains low-confidence predictions for evaluation. |
docs/faq.md |
Expands documented model support. |
docs/changelog.md |
Finalizes and organizes release notes. |
🧠 Review effort: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #2742 +/- ##
=======================================
Coverage 94% 94%
=======================================
Files 83 83
Lines 13489 13489
=======================================
Hits 12672 12672
Misses 817 817 🚀 New features to boost your workflow:
|
|
Thanks for including |
v0.31.0 — Depth, moving cameras and pose mAP
📋 Summary
supervision now sees depth: load depth maps from your model or stereo rig, measure how far each object is, and draw the map.
sv.DepthMapmeasures the distance to every detection and colours depth over any image, no OpenCV needed.PolygonZoneandLineZonekeep counting in the right place while the camera pans.KeyPointMeanAveragePrecisionscores pose models the waypycocotoolsdoes.DetectionsandKeyPoints.MeanAveragePrecisionruns far faster on crowded images and lets you raise the detection cap.It's a drop-in upgrade if 0.30.x showed you no deprecation warnings, apart from four output changes.
sv.ByteTrackwith thesupervision.trackerpackage,supervision.keypoint,sv.LMM, the legacysv.MeanAveragePrecisionand a few helpers are gone; the Migration guide has the swaps.✨ Spotlights / highlights
Depth maps: load, measure and draw
sv.DepthMapholds metric depth, stereo disparity or relative depth for one frame, and keeps track of which one it is.sv.DepthCameraconverts disparity to metres,measure_detectionswrites the median depth under each object todetections.data("depth_m"when the map can give metres), andsv.DepthAnnotatorcolours the map over an image without OpenCV.sv.DepthClipRangekeeps one colour scale across a whole video, so colours don't flicker between frames. Loaders read Roboflow Inference, Ultralytics, Transformers, and 16-bit PNG and PFM dataset files such as KITTI and Middlebury. (#2691, #2692, #2693, #2694)Zones that follow the camera
Zones used to assume a fixed camera; when it panned, the scene slid out from under the zone.
PolygonZone.triggerandLineZone.triggernow take an optional per-framecoord_transformthat maps detection anchors back into the frame the zone was drawn on. Any object withabs_to_relandrel_to_absworks, as described by the newsv.CoordinatesTransformationprotocol, including the transformations from thetrackersmotion estimator. Drawing is unchanged, andcoord_transform=Nonekeeps current results. (#2657)COCO keypoint mAP for pose models
sv.metrics.KeyPointMeanAveragePrecisionscoressv.KeyPointspredictions by Object Keypoint Similarity at ten thresholds from 0.50 to 0.95, and its scores agree withpycocotoolsCOCOeval(..., "keypoints"). COCO greedy matching is now vectorized for box and keypoint mAP. In the benchmark reported with that change, one image with 1000 predictions and a 1000-detection cap dropped from 35.9 s to 0.5 s.MeanAveragePrecisionalso takesmax_detection_thresholdsfor scenes with more than 100 objects. (#2687, #2733, #2716)More models, and the matcher behind the metrics
sv.Detections.from_vlmparses Kosmos-2 grounding results (sv.VLM.KOSMOS_2) and Gemini 3.6 and 3.7 structured boxes and polygon masks.sv.KeyPoints.from_mediapipeloads MediaPipe hand landmarks, withclass_id0 for a left hand and 1 for a right hand.sv.match_detectionsexposes the one-to-one greedy IoU matcher the metrics use, for comparing two models or auditing labels against predictions. (#1903, #2504, #2283, #2557)🔄 Migration guide
No breaking changes beyond the APIs deprecated in 0.26–0.28 and scheduled for removal in 0.31.0. If 0.30.x printed no deprecation warnings for your code, only the four output changes at the end of this section can affect it.
sv.ByteTrackand thesupervision.trackerpackageByteTrackTrackerfrom thetrackerspackage (pip install trackers); callupdate()instead ofupdate_with_detections()supervision.keypointsupervision.key_pointssv.LMM,Detections.from_lmmsv.VLM,Detections.from_vlmsv.MeanAveragePrecision(supervision.metrics.detection)sv.metrics.MeanAveragePrecisionsv.denormalize_boxes(normalized_xyxy=...)sv.denormalize_boxes(xyxy=...)supervision.dataset.utils.mask_to_rle/rle_to_masksv.mask_to_rle/sv.rle_to_maskensure_cv2_image_for_annotationensure_cv2_image_for_class_method(supervision.utils.conversion)ensure_pil_image_for_annotationensure_pil_image_for_class_method(supervision.utils.conversion)ensure_cv2_image_for_processingensure_cv2_image_for_standalone_function(supervision.utils.conversion)create_tiles,overlay_image(alsosv.overlay_image),validate_keypoint_confidence,validate_keypoints_fieldsFour behaviour changes can alter output:
sv.Detectionsraises on non-finite boxes,sv.CSVSinkwrites arrays as JSON lists,ConfusionMatrix.from_detectionsrejects lists of different length, and multi-classmAR @ Kscores follow COCO. Details under Changed and Fixed.📝 Notable changes
🚀 Added
sv.DepthMap,sv.DepthAnnotator,sv.DepthClipRangeandsv.DepthCamera, withto_depth,measure_detections,resize,crop,value_at,DepthAnnotator(scale="metric"), and loadersfrom_inference,from_ultralytics,from_transformers,from_png16andfrom_pfm. (feat(depth): addDepthMapandDepthAnnotator#2691, feat(depth): addDepthClipRangefor one colour scale across video #2692, feat(depth): measure distance with sv.DepthCamera and measure_detections #2693, feat(depth): load depth maps from Inference, Ultralytics, Transformers and dataset files #2694)PolygonZone.triggerandLineZone.triggeracceptcoord_transform, typed by the newsv.CoordinatesTransformationprotocol. (feat(detection): let zones follow camera motion withcoord_transform#2657)sv.metrics.KeyPointMeanAveragePrecisionforsv.KeyPoints, matchingpycocotoolskeypoint evaluation. (feat(metrics): add COCO keypoint mAP (OKS) forsv.KeyPoints#2687)max_detection_thresholdsonMeanAveragePrecision; the default(1, 10, 100)is unchanged. (feat(metrics): make dense-scene mAP detection limits configurable #2716)sv.ConfusionMatrix.from_detectionsandbenchmarkacceptmetric_target=MetricTarget.MASKSand match by mask IoU, on dense masks orCompactMask. (feat(metrics): scoreConfusionMatrixon masks withMetricTarget.MASKS#2612)MetricResultbase class for metric results, plusaggregate_metric_results()andplot_aggregate_metric_results()to compare several results in one table or grouped bar chart. (feat(metrics): addMetricResultABC and aggregate comparison functions #2498)sv.match_detectionsreturns one-to-one greedy IoU matches and the unmatched indices on each side, optionally per class. (feat: exposesv.match_detectionsas a public matching primitive #2557)sv.VLM.KOSMOS_2insv.Detections.from_vlm, one detection per grounded region. (feat(Detections): add support for Kosmos-2 #1903)sv.VLM.GOOGLE_GEMINI_3_6andsv.VLM.GOOGLE_GEMINI_3_7parse the structured{"boxes": [...]}format, including normalized polygon masks. (Add Gemini 3.6 and 3.7 structured VLM output support #2504)sv.KeyPoints.from_mediapipeloads hand landmarks from the TasksHandLandmarkerand the legacyHandssolution, with a new hand skeleton,class_id0 for left and 1 for right, and the handedness score indata["handedness_score"]. (feat: add MediaPipe hand landmark support #2283)🌱 Changed
sv.Detectionsvalidatesxyxy: non-finite (NaN, inf) or non-numeric boxes now raiseValueErrorinstead of failing later. (Validate Detections xyxy boxes for finiteness #2503)sv.ConfusionMatrix.from_detectionsraises whenpredictionsandtargetsdiffer in length, instead of scoring the shorter list. (feat(metrics): scoreConfusionMatrixon masks withMetricTarget.MASKS#2612)sv.CSVSinkwrites NumPy arrays indataandcustom_dataas JSON lists instead of NumPy's truncatedstr()form; parse array cells withjson.loads. (fix: write array-valued data to CSV as parseable lists #2707)sv.Detections.with_nmmandsv.mask_non_max_mergemergeCompactMaskunions without full-image allocations; the error for mismatched image shapes now names both shapes. (perf(detection): keep compact mask NMM unions in RLE form #2606, perf(detection): dense-fallback fragmented unions #2616)sv.Detections.from_inference(compact_masks=True)crops each polygon mask to the polygon instead of the whole image, cutting time and memory for many polygons on large images. (perf(detection): crop compact polygon masks to the polygon infrom_inference#2678)MeanAveragePrecisionandKeyPointMeanAveragePrecisionis vectorized; results are unchanged. (perf(metrics): vectorize COCO greedy matching in mAP evaluation #2733)sv.ComparisonAnnotatorbuilds its mask union fromCompactMaskcrops in place instead of allocating a full(N, H, W)stack. (refactor: vectorize_mask_from_maskloop #2495)❌ Removed
sv.ByteTrackand thesupervision.trackerpackage (usetrackers.ByteTrackTracker), thesupervision.keypointmodule (usesupervision.key_points),sv.LMMandDetections.from_lmm(usesv.VLMandfrom_vlm), the legacysv.MeanAveragePrecision(usesv.metrics.MeanAveragePrecision),create_tiles,overlay_image,ensure_cv2_image_for_annotation,ensure_pil_image_for_annotationandensure_cv2_image_for_processing(use theensure_*_for_class_method/ensure_cv2_image_for_standalone_functiondecorators),validate_keypoint_confidence,validate_keypoints_fields, thenormalized_xyxyargument ofsv.denormalize_boxes(usexyxy), and thesupervision.dataset.utilsimport path formask_to_rle/rle_to_mask. (chore(deprecation): remove scheduled for removal in0.31.0[rebase&merge] #2582)🔧 Fixed
sv.Detections.from_ultralyticsno longer shifts or truncates segmentation masks when letterbox padding is fractional. (fix(detection): align Ultralytics masks after letterbox padding #2739)sv.Detectionswith a Python list of booleans now selects list-valueddatawith the same mask as the arrays; it was read as positions. (fix(detection): index list data with a list of booleans as a mask #2737)sv.move_boxesandInferenceSlicerno longer wrap integer coordinates when an offset crosses the dtype's range. (fix(detection): prevent integer overflow when moving boxes #2734)sv.Detections.box_aspect_rationo longer overflows on integer boxes at large coordinates. (fix(detections): Prevent integer aspect-ratio overflow #2729)BlurAnnotatorandPixelateAnnotatorkeep a(H, W, 1)grayscale channel axis instead of failing with a broadcasting error. (fix(annotators): preserve grayscale channel axis in blur and pixelation #2725)line,polylinesanddrawContoursoutlines match OpenCV'sLINE_8pixels forthickness2 or more. (fix(cv2): draw thick lines and polylines like OpenCV without OpenCV #2727)fillPolypaints the same boundary pixels as OpenCV, sopolygon_to_maskandPolygonZoneagree across backends. (Fix NumPy fillPoly boundary rasterization #2730)resizewithINTER_NEARESTsamples the same source pixels as OpenCV, which also alignssv.CompactMask.resizeacross backends. (fix(cv2): match OpenCV's nearest-neighbour sampling grid in the resize fallback #2722)sv.process_videostops reading the source when a callback or frame write fails, instead of decoding the rest of the video before raising. (fix(video): cancel source reader after processing failure #2720)smart_position=Trueseparate labels whose boxes share a center; before, only the last label was visible. (fix(annotators): separate smart-positioned labels that share a center #2718)MeanAveragePrecisionkeeps corner precision at large coordinates and puts objects in the right size bucket. (fix(metrics): preserve oriented-box precision in mAP #2717)sv.KeyPointskeeps all three coordinates when selecting a single key point with a NumPy integer index. (fix(key_points): Preserve coordinate depth in single-point selection #2715)sv.CompactMaskaccepts NumPy'scopykeyword, so NumPy 2 no longer warns on conversion. (fix(compact_mask): Honor NumPy array copy requests #2708)sv.CompactMask.resizematches dense nearest-neighbour resizing, including crops that become empty. (fix(compact_mask): Match dense nearest-neighbor resizing #2697, fix: makeCompactMask.resizematch dense nearest-neighbour resize #2705)DetectionDataset.as_yolo,as_pascal_vocandas_labelmeexport a mask with holes as one instance instead of one extra instance per hole;approximate_mask_with_polygonsinsupervision.dataset.utilsgains the opt-inbridge_holesparameter that does this. (fix: keep mask holes from becoming extra instances in dataset export #2703)sv.metrics.MeanAverageRecallapplies themAR @ Klimit per class per image, as COCO does; multi-class scores were too low. (fix(metrics): limitMeanAverageRecalldetections per image and class #2701)sv.metrics.MeanAveragePrecisionscores perfect predictions as exactly1.0instead of 0.99999988. (feat(metrics): add COCO keypoint mAP (OKS) forsv.KeyPoints#2687)from_vlmwith Gemini 2.5 or 3.5 keeps a mask pixel only where the score exceeds 127 of 255; masks grew by half a mask pixel per side. (fix(detection): binarize Gemini 2.5 mask probabilities at the midpoint #2589)from_vlmwith Gemini 2.5 or 3.5 keeps masks for the detections that passclasseswhen a filtered-out item has no mask. (Add Gemini 3.6 and 3.7 structured VLM output support #2504)from_vlmkeepsclass_idinteger-typed when aclassesfilter removes every detection for PaliGemma, DeepSeek-VL2 and Gemini 2.0. (refactoring and simplifications #2556)from_ultralyticsforDetections,KeyPointsandClassificationsaccepts NumPy-backed results, includingResults.numpy(). (Fix conversion of NumPy-backed Ultralytics results #2710)🏆 Contributors
KeyPointMeanAveragePrecisionand fixed perfect-prediction mAP scoring.DepthMap,DepthAnnotator,DepthClipRange,DepthCameraand model loaders.coord_transform.max_detection_thresholdstoMeanAveragePrecision.ConfusionMatrix.ComparisonAnnotatorwith compact masks.sv.match_detections.from_vlm.from_vlm.KeyPoints.from_mediapipe.Detectionsreject non-finite or non-numeric boxes.CSVSinkarray output,CompactMask.resizeand mask holes in dataset export.Detections.from_inferencewith compact masks.with_nmmfor compact masks.box_aspect_ratiooverflow,CompactMaskconversion and resize, single-pointKeyPointsselection and NumPy-backed Ultralytics results.Detectionsindexing andsmart_positionlabel overlap.process_videocleanup and box-area overflow in metrics.resizesampling without OpenCV.fillPolyrasterization without OpenCV.MeanAverageRecallscoring.from_vlmclass_iddtype, followed up onwith_nmmperformance, and maintained docs, CI and release infrastructure.Automated contributions: @dependabot, @pre-commit-ci, @copilot
Full changelog: 0.30.0...0.31.0