What's new
π KeyPoints.with_nms() β NMS for pose estimation
import supervision as sv
key_points = model.predict(image) # sv.KeyPoints
key_points = key_points.with_nms(threshold=0.5) # removes duplicate skeletonsDerives axis-aligned bounding boxes from each skeleton's valid (non-zero and visible) keypoints, then applies standard box NMS. Supports class_agnostic mode and any OverlapMetric (IOU, IOS). Raises ValueError if detection_confidence is not set.
feat-keypoints-with-nms-compressed.mp4
Notable changes
Bug fixes
-
sv.DetectionDataset.as_pascal_vocno longer mutates bounding boxes (#2341) Previously, every export shifted every bounding box by +1 px in-place. A second call compounded the shift. Fixed by rebinding to a new array; on-disk XML output is unchanged. -
sv.Precisionandsv.F1Scorecorrectly count background false positives (#2331) Predictions on images with no ground-truth objects, and predictions of classes absent from any annotation, were previously ignored. UnderMICROandMACROaveraging they are now counted as false positives.WEIGHTEDaveraging is unchanged. Users should re-evaluate existing metric results after upgrading. -
sv.DetectionsSmootherworks with confidence-free detections (#2333) The smoother no longer raises when detections have no confidence scores. Confidence is averaged over the frames that carry it; tracks without any confidence produceNone. -
sv.Detections.from_vlmis robust to malformed Gemini/Qwen output (#2342) Valid JSON that is not a list, or whose elements are not dicts, now degrades to emptyDetectionsinstead of raisingTypeError. A malformed mask value in Gemini 2.5 responses no longer misaligns thexyxy/confidence/masksarrays. -
sv.JSONSinkserializes NumPy scalars incustom_data(#2334)np.int64frame indices and other NumPy scalars incustom_datano longer raiseTypeErrorat flush time. NumPy arrays are serialized as lists. The file handle closes even when serialization fails. -
sv.approximate_polygonrespects the point-count budget (#2332) The function now returns at mostfloor(N * (1 - percentage))points (minimum 3). Previously it could return more points than requested.epsilon_stepis now validated to be positive. -
COCO export preserves all segments for multi-part masks (#2322) Previously, only the first polygon was written when a non-crowd detection had disjoint mask segments. All polygon parts are now written.
Performance
-
sv.HaloAnnotatoris ~4Γ faster withCompactMaskdetections (#2339)HaloAnnotatornow uses the same optimized CompactMask paint path asMaskAnnotator. Previously it materialized each mask full-frame; now it operates on the bounding-box crop. Annotated output is unchanged. -
Mask IoU uses less peak memory (#2323) Mask IoU computation now uses matrix multiplication on flattened masks instead of an explicit
(N, M, H, W)tensor. For masks larger than 4096Γ4096 px, computation promotes to float64 automatically. Results are numerically identical. -
sv.mask_to_xyxyandsv.KeyPoints.as_detectionsvectorized (#2330) Both functions now use batched NumPy operations instead of per-element loops. Outputs are bit-identical.
Contributors
- Ruben Haisma (@RubenHaisma, LinkedIn) β VLM robustness, Pascal VOC export fix, DetectionsSmoother, JSONSink, metrics correctness, polygon budgeting, vectorization
- Agis Kounelis (@kounelisagis, LinkedIn) β HaloAnnotator perf, mask IoU matmul, mask_to_xyxy/KeyPoints.as_detections vectorization, OBB cookbook
- Piotr Skalski (@SkalskiP, LinkedIn) β
KeyPoints.with_nms() - Abdelrahman Gomaa (@abdogomaa201099, LinkedIn) β COCO multi-polygon export
Full Changelog: 0.29.0...0.29.1