Skip to content

supervision-0.31.1

Latest

Choose a tag to compare

@Borda Borda released this 20 Oct 18:13

v0.31.1 β€” Recall that matches COCO, boxes that don't overflow

A bug-fix release: recall scores now agree with COCO, and half-precision boxes stop overflowing.

  • MeanAverageRecall skips crowd regions and matches predictions in confidence order, like pycocotools.
  • COCO segmentations loaded without an area field no longer make mAP return -1.
  • float16 boxes keep finite areas, and mAP and with_nmm stop overflowing on narrow coordinate types.
  • Mask and halo annotators draw on grayscale scenes, and vertex annotators accept (x, y, z) points.
  • Without OpenCV, ellipses and thick circles render like OpenCV 5, and grayscale images save correctly.

Drop-in upgrade, no code changes. mAR values can move: up on COCO data with crowd annotations, and in either direction where confidence order now decides which prediction claims a target.

✨ Spotlights / highlights

Recall that matches COCO

sv.metrics.MeanAverageRecall used to count COCO crowd regions as missed objects and to pair predictions with the highest-IoU target first. It now leaves out targets with data["iscrowd"] or data["ignore"] set, the same rule MeanAveragePrecision uses. It also matches predictions in descending confidence order with COCO's tie rule, and counts an oriented-box IoU of exactly 0.55, 0.6, 0.8 or 0.85 as a match at that threshold. One target, one crowd target and a perfect prediction now score 1.0 instead of 0.5. (#2750, #2758, #2752)

import numpy as np
import supervision as sv
from supervision.metrics import MeanAverageRecall

targets = sv.Detections(
    xyxy=np.array([[0, 0, 10, 10], [20, 20, 30, 30]], dtype=float),
    class_id=np.array([0, 0]),
    data={"iscrowd": np.array([0, 1])},
)
predictions = sv.Detections(
    xyxy=np.array([[0, 0, 10, 10]], dtype=float),
    class_id=np.array([0]),
    confidence=np.array([0.9]),
)
MeanAverageRecall().update(predictions, targets).compute().mAR_at_100  # 1.0

Half-precision boxes that stay finite

A 256Γ—256 box in float16 has an area of 65,536, which is past float16's maximum, so Detections.box_area returned inf and area filters dropped it. Box areas of float16 detections are now computed and returned in float32, and MeanAveragePrecision and with_nmm no longer overflow on float16 or narrow integer coordinates either. COCO segmentations loaded with masks but without an area field now get it from the decoded mask, so those targets stay in their size bucket instead of turning mAP into -1. (#2764, #2743, #2753, #2763)

import numpy as np
import supervision as sv

detections = sv.Detections(
    xyxy=np.array([[0, 0, 256, 256], [0, 0, 0.01, 0.01]], dtype=np.float16)
)
detections.box_area  # array([6.5536000e+04, 1.0004273e-04], dtype=float32)

Grayscale scenes and 3D keypoints in annotators

sv.MaskAnnotator and sv.HaloAnnotator raised ValueError on single-channel images. They now accept (H, W), (H, W, 1) and Pillow "L" scenes, painting the gray value OpenCV would write for the same color. VertexAnnotator and the vertex-ellipse annotators draw (x, y, z) keypoints from their x and y, where they used to fail on tuple unpacking. (#2755, #2759)

import numpy as np
import supervision as sv

scene = np.zeros((100, 100), dtype=np.uint8)
mask = np.zeros((1, 100, 100), dtype=bool)
mask[0, 20:60, 20:60] = True
detections = sv.Detections(
    xyxy=np.array([[20, 20, 60, 60]], dtype=float), mask=mask, class_id=np.array([0])
)
sv.MaskAnnotator().annotate(scene.copy(), detections).shape  # (100, 100)

key_points = sv.KeyPoints(xy=np.array([[[10, 10, 0.5], [50, 50, 1.0]]], dtype=np.float32))
sv.VertexAnnotator().annotate(np.zeros((64, 64, 3), dtype=np.uint8), key_points)

Drawing without OpenCV, closer to OpenCV

The NumPy fallback used when OpenCV is not installed now ports OpenCV's ellipse rasterization, and thick circle outlines are centred on the radius instead of shrinking inward by half their thickness. Both match OpenCV 5.0 pixel for pixel in the reference tests. Without OpenCV, this changes the pixels drawn by EllipseAnnotator, RoundBoxAnnotator, the vertex-ellipse keypoint annotators, CircleAnnotator and DotAnnotator outlines. Image writing now accepts (H, W, 1) grayscale arrays and saves BGRA images as JPEG, and video reading handles files whose audio stream comes before the video stream. (#2740, #2765, #2754, #2746)

πŸ”„ Migration guide

No migration required for this release.

πŸ“ Notable changes

πŸ”§ Fixed

MeanAverageRecall and COCO

  • sv.metrics.MeanAverageRecall counted COCO crowd and ignored targets as missed objects and paired predictions by highest IoU first; it now skips those targets and matches in descending confidence order with COCO's last-target tie rule, as COCO does. (#2750, #2758)
  • Oriented-box MeanAverageRecall, Precision, Recall and F1Score missed matches whose IoU was exactly 0.55, 0.6, 0.8 or 0.85, because the IoU was float64 and the thresholds float32. (#2752)

Overflow-safe boxes

  • Detections.box_area and box-based Detections.area overflowed to infinity for ordinary float16 boxes; they now compute and return float32. (#2764)
  • sv.metrics.MeanAveragePrecision overflowed box extents and areas for float16 or narrow integer coordinates, so perfect large boxes scored -1 or landed in the wrong size bucket. (#2743)
  • sv.Detections.with_nmm overflowed its area-weighted confidence for float16 boxes and, at extreme coordinates, for integer and float32 boxes. (#2753)
  • COCO loading with masks left segmented annotations without an area field with a NaN area, which pushed them out of every mAP size bucket; the area now comes from the decoded mask. (#2763)

Masks and polygons

  • resize_masks returned an empty array when downscaling very narrow masks; it now keeps at least one pixel per axis. (#2762)
  • sv.filter_polygons_by_area and sv.polygon_to_xyxy raised ValueError on empty polygons; they now treat them as zero area and an all-zero box. (#2761)

Annotators

  • sv.MaskAnnotator and sv.HaloAnnotator raised ValueError on grayscale scenes. (#2755)
  • VertexAnnotator and the vertex-ellipse annotators raised a tuple-unpacking error on three-coordinate keypoints; they now draw from x and y. (#2759)
  • sv.MaskAnnotator widened its blend region to the boxes of all-empty masks, including CompactMask, copying and blending outside the foreground. (#2741)

Without OpenCV

  • The fallback ellipse painted different pixels from OpenCV for thick strokes, fills and arcs; it now ports OpenCV's rasterization. (#2740)
  • The fallback circle grew thick outlines inward from the bounding box, shrinking them by half their thickness; they are now centred on the radius. (#2765)
  • Image writing rejected (H, W, 1) grayscale arrays and lost BGRA images saved as JPEG. (#2754)
  • Video reading failed on files whose audio stream comes before the first video stream. (#2746)

πŸ† Contributors

Welcome to our first-time contributors, Ghanashyam V Narayan and jorge!

  • NIKHIL (@Nikhi00718) β€” fixed overflow in box areas, mAP and with_nmm, derived missing COCO areas, and fixed image writing and video reading without OpenCV.
  • Kaushik Reddy Lingireddy (@Lingikaushikreddy) β€” made MeanAverageRecall skip crowd targets and match by confidence, and fixed oriented-box threshold matching.
  • peng xiang (@px12811) β€” ported OpenCV's ellipse rasterization to the fallback and fixed mAR tie-breaking.
  • A Aswanth Raj (@aswanth-07) β€” fixed three-coordinate keypoint drawing and narrow-mask resizing.
  • Mohammad Hijjawi (@MohammadHijjawi97) β€” made MaskAnnotator and HaloAnnotator work on grayscale scenes.
  • kevin (@kevin9327) β€” centred thick fallback circles on their radius.
  • Ghanashyam V Narayan (@ghanashyam03) β€” made the polygon helpers accept empty polygons.
  • jorge (@jorge-asenjo) β€” kept empty compact masks out of the mask blend region.
  • Jirka Borovec (@Borda) β€” prepared the release.

Full changelog: 0.31.0...0.31.1