Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Supervision User Guide

Generated June 2026 from roboflow/supervision at b18a30e

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Supervision is an open-source Python library by Roboflow that gives you the reusable building blocks for computer vision applications. It takes the raw output of any detection, segmentation, keypoint, or classification model and turns it into a single, consistent object you can annotate, filter, track, count, export, and benchmark — without rewriting glue code for every model you try.

This guide is task-oriented. Start with the Quick Start, install the package, learn the one object every workflow revolves around (sv.Detections), then jump to the task you need: drawing boxes and masks, filtering predictions, tracking objects in video, counting in zones, processing datasets, or measuring model accuracy.

Note

Supervision is model-agnostic. It does not run inference itself — you bring a model (Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, a VLM, and more) and Supervision handles everything that happens to the predictions afterward.


1. Quick Start

If you already have a detection model, here is the complete loop: run inference, convert to Supervision's format, and draw the results.

import cv2
import supervision as sv
from ultralytics import YOLO

# 1. Run any model
model = YOLO("yolov8n.pt")
image = cv2.imread("dog.jpeg")
results = model(image)[0]

# 2. Convert the output into a unified Detections object
detections = sv.Detections.from_ultralytics(results)

# 3. Draw the predictions
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()

annotated = box_annotator.annotate(scene=image.copy(), detections=detections)
annotated = label_annotator.annotate(scene=annotated, detections=detections)

sv.plot_image(annotated)

That is the core pattern for every model Supervision supports. Only line 2 changes: swap from_ultralytics for from_inference, from_transformers, from_sam, and so on. Everything downstream — annotators, filters, trackers, zones, metrics — works the same regardless of which model produced the predictions.

Tip

Don't have a test image? Download the one used throughout the Roboflow tutorials:

wget https://media.roboflow.com/notebooks/examples/dog.jpeg

2. Installation

Supervision runs on Python 3.9 or newer (3.9–3.14 are officially supported) on macOS, Windows, and Linux.

pip (recommended)

pip install supervision

uv

uv pip install supervision

For a uv-managed project:

uv add supervision

poetry

poetry add supervision

conda / mamba

conda install -c conda-forge supervision

Optional extras

Some features pull in extra dependencies. Install them only when you need them:

Extra Command Adds
Metrics pip install "supervision[metrics]" pandas, required only for tabular metric output

Note

The legacy headless and desktop install targets were removed. pip install supervision[headless] still works — it installs the base library and harmlessly warns that the extra no longer exists. The base package is already headless-friendly.

Install from source (development)

git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
cd supervision

python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip

pip install -e "."

Verify the installation

import supervision as sv
print(sv.__version__)
0.29.0

Important

Supervision installs CPU dependencies only (NumPy, OpenCV, Pillow, SciPy, Matplotlib). It does not install PyTorch, Ultralytics, or any model framework — you choose and install those yourself based on the model you want to run.


3. The Detections Object (Core Concept)

Almost everything in Supervision flows through one class: sv.Detections. It is a container that normalizes the output of any supported model into the same set of NumPy arrays.

Attribute Shape Meaning
xyxy (n, 4) Bounding boxes as [x1, y1, x2, y2] in pixels
mask (n, H, W) or None Boolean segmentation masks, when available
confidence (n,) or None Per-detection confidence scores
class_id (n,) or None Integer class IDs
tracker_id (n,) or None Persistent IDs assigned by a tracker
data dict Extra per-detection fields, e.g. data["class_name"]
metadata dict Collection-level info (video name, timestamp, …)

You rarely build a Detections by hand. Instead you use a from_* connector for your model.

Connectors — load predictions from any model

Method Source framework
Detections.from_inference(result) Roboflow Inference
Detections.from_ultralytics(result) Ultralytics YOLO (detect, segment, OBB)
Detections.from_transformers(result, id2label=...) Hugging Face Transformers
Detections.from_sam(result) Segment Anything Model
Detections.from_sam3(result, resolution_wh=...) SAM 3
Detections.from_detectron2(result) Detectron2
Detections.from_mmdetection(result) MMDetection / MMYOLO
Detections.from_yolo_nas(result) YOLO-NAS (super-gradients)
Detections.from_yolov5(result) YOLOv5
Detections.from_deepsparse(result) Neural Magic DeepSparse
Detections.from_paddledet(result) PaddleDetection
Detections.from_tensorflow(result, resolution_wh=...) TensorFlow Hub
Detections.from_ncnn(result) NCNN
Detections.from_easyocr(result) EasyOCR
Detections.from_azure_analyze_image(result) Azure AI Vision 4.0
Detections.from_vlm(vlm=..., result=..., ...) Vision-language models (see §11)

Tip

Every connector returns the same Detections type. This is the whole point of Supervision: write your annotation, tracking, and counting logic once, then change models freely by changing only the connector line.

Useful properties and methods

Member Returns Notes
len(detections) int Number of detections
detections.area (n,) Mask area if masks present, else box area
detections.box_area (n,) Bounding-box area in pixels
detections.box_aspect_ratio (n,) Width / height of each box
detections.get_anchors_coordinates(anchor) (n, 2) Anchor points (see Position)
detections.with_nms(threshold=0.5) Detections Non-maximum suppression
detections.with_nmm(threshold=0.5) Detections Non-maximum merge
Detections.merge([d1, d2, ...]) Detections Concatenate multiple objects
Detections.empty() Detections An empty object
detections.is_empty() bool True when there are no detections
detections["class_name"] array Access a data field directly

4. Detect and Annotate

Supervision ships a rich catalog of annotators — composable objects that each draw one kind of visual overlay. They all share the same call shape: annotator.annotate(scene=image, detections=detections), and each returns the modified image so you can chain them.

Boxes and labels

Ultralytics

import cv2
import supervision as sv
from ultralytics import YOLO

model = YOLO("yolov8n.pt")
image = cv2.imread("dog.jpeg")
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)

box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()

annotated = box_annotator.annotate(scene=image, detections=detections)
annotated = label_annotator.annotate(scene=annotated, detections=detections)

Inference

import cv2
import supervision as sv
from inference import get_model

model = get_model(model_id="yolov8n-640")
image = cv2.imread("dog.jpeg")
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)

box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()

annotated = box_annotator.annotate(scene=image, detections=detections)
annotated = label_annotator.annotate(scene=annotated, detections=detections)

Custom labels

By default LabelAnnotator prints each detection's class name (falling back to class ID, then index). Pass your own labels list to override:

labels = [
    f"{class_name} {confidence:.2f}"
    for class_name, confidence
    in zip(detections["class_name"], detections.confidence)
]

annotated = box_annotator.annotate(scene=image, detections=detections)
annotated = label_annotator.annotate(
    scene=annotated, detections=detections, labels=labels)

Segmentation masks

For a segmentation model, swap BoxAnnotator for MaskAnnotator — it is a drop-in replacement.

mask_annotator = sv.MaskAnnotator()
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER_OF_MASS)

annotated = mask_annotator.annotate(scene=image.copy(), detections=detections)
annotated = label_annotator.annotate(scene=annotated, detections=detections)

The annotator catalog

Annotator Draws
BoxAnnotator Bounding-box rectangles
RoundBoxAnnotator Boxes with rounded corners
BoxCornerAnnotator Corner brackets only
OrientedBoxAnnotator Rotated (OBB) boxes
ColorAnnotator Semi-transparent filled boxes
MaskAnnotator Segmentation masks
PolygonAnnotator Mask outlines as polygons
HaloAnnotator Soft glow around masks
EllipseAnnotator Ellipse under each object (sports-style)
CircleAnnotator Circle around each object
DotAnnotator A dot at an anchor point
TriangleAnnotator A triangle marker above each object
LabelAnnotator Text labels with background
RichLabelAnnotator Labels with custom (e.g. non-Latin) fonts
IconAnnotator A custom PNG icon per detection
BlurAnnotator Blurs the detected regions
PixelateAnnotator Pixelates the detected regions
HeatMapAnnotator Accumulated heatmap over a video
TraceAnnotator Motion trails for tracked objects
PercentageBarAnnotator A progress-style bar per detection
CropAnnotator Magnified crops of each detection
BackgroundOverlayAnnotator Dims everything outside the detections
ComparisonAnnotator Side-by-side comparison of two detection sets

Common annotator options

Most annotators accept the same core constructor arguments:

Argument Default Meaning
color ColorPalette.DEFAULT A single Color, a ColorPalette, or a hex string
thickness 2 Line thickness in pixels
color_lookup ColorLookup.CLASS How colors map to objects: INDEX, CLASS, or TRACK

MaskAnnotator and ColorAnnotator add opacity (default 0.5). LabelAnnotator adds text_color, text_scale, text_padding, text_position, border_radius, and smart_position (spreads overlapping labels apart).

Tip

Set color_lookup=sv.ColorLookup.TRACK once you are tracking objects, so every object keeps the same color across all frames of a video.


5. Filter Detections

Detections supports NumPy-style boolean indexing. This is the fastest, most expressive way to refine predictions — no helper methods to memorize.

import numpy as np
import supervision as sv

# Keep only class 0
detections = detections[detections.class_id == 0]

# Keep a set of classes
detections = detections[np.isin(detections.class_id, [0, 2, 3])]

# Confidence threshold
detections = detections[detections.confidence > 0.5]

# Minimum pixel area
detections = detections[detections.area > 1000]

# Relative area (drop objects larger than 80% of the frame)
h, w, _ = image.shape
detections = detections[(detections.area / (h * w)) < 0.8]

# Box dimensions
box_w = detections.xyxy[:, 2] - detections.xyxy[:, 0]
box_h = detections.xyxy[:, 3] - detections.xyxy[:, 1]
detections = detections[(box_w > 200) & (box_h > 200)]

Combine any conditions with & (and) / | (or):

detections = detections[(detections.confidence > 0.7) & (detections.class_id == 2)]

Remove duplicates with NMS

detections = detections.with_nms(threshold=0.5)

Note

detections.area returns mask area when masks are present and box area otherwise. Use detections.box_area when you always want bounding-box area, and detections.box_aspect_ratio to filter by shape.


6. Track Objects in Video

Tracking assigns a persistent ID to each object so you can follow it across frames. Supervision processes video through sv.process_video, which calls your per-frame callback.

import numpy as np
import supervision as sv
from ultralytics import YOLO

model = YOLO("yolov8n.pt")
tracker = sv.ByteTrack()
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
trace_annotator = sv.TraceAnnotator()

def callback(frame: np.ndarray, index: int) -> np.ndarray:
    results = model(frame)[0]
    detections = sv.Detections.from_ultralytics(results)
    detections = tracker.update_with_detections(detections)

    labels = [
        f"#{tracker_id} {class_name}"
        for class_name, tracker_id
        in zip(detections["class_name"], detections.tracker_id)
    ]

    annotated = box_annotator.annotate(frame.copy(), detections=detections)
    annotated = label_annotator.annotate(annotated, detections=detections, labels=labels)
    return trace_annotator.annotate(annotated, detections=detections)

sv.process_video(
    source_path="people-walking.mp4",
    target_path="result.mp4",
    callback=callback,
)

TraceAnnotator overlays each tracked object's recent path, making movement patterns easy to see.

Warning

sv.ByteTrack is deprecated since supervision-0.28.0 and will be removed in supervision-0.30.0. The recommended replacement is ByteTrackTracker from the separate trackers package (pip install trackers). In the new package the update method is named update() instead of update_with_detections().

ByteTrack tuning

Parameter Default Effect
track_activation_threshold 0.25 Min confidence to start a track
lost_track_buffer 30 Frames to keep a lost track alive (occlusion handling)
minimum_matching_threshold 0.8 Track-to-detection matching strictness
frame_rate 30 Video FPS (used to scale the lost-track buffer)
minimum_consecutive_frames 1 Frames an object must persist to become a valid track

Smoothing shaky boxes

Wrap the tracker output in DetectionsSmoother to average box coordinates over the last few frames:

smoother = sv.DetectionsSmoother()      # default length = 5 frames

detections = tracker.update_with_detections(detections)
detections = smoother.update_with_detections(detections)

Caution

DetectionsSmoother requires tracker_id (run a tracker first) and is not compatible with segmentation masks.


7. Count Objects in Zones

Polygon zones

A PolygonZone tests which detections fall inside an arbitrary region. Its trigger() method returns a boolean mask you can use to filter or count.

import numpy as np
import supervision as sv

polygon = np.array([[100, 200], [200, 100], [300, 200], [200, 300]])
zone = sv.PolygonZone(polygon=polygon)

mask = zone.trigger(detections=detections)   # boolean array, one per detection
detections_in_zone = detections[mask]
count = zone.current_count                   # number currently inside

Draw the zone and its live count with PolygonZoneAnnotator:

zone_annotator = sv.PolygonZoneAnnotator(
    zone=zone,
    color=sv.Color.RED,
    thickness=4,
)
frame = zone_annotator.annotate(scene=frame)

Tip

Generate polygon coordinates visually with the free PolygonZone web tool — upload a frame, click the region, and copy the NumPy array it produces.

Note

By default a detection counts as "inside" when its bottom-center point is in the polygon. Change which anchor(s) are tested with PolygonZone(polygon=..., triggering_anchors=(sv.Position.CENTER,)).

Line zones (crossing counts)

A LineZone counts objects that cross a line, separately tallying each direction. Line crossing needs tracker_id, so run a tracker first.

start = sv.Point(x=0, y=500)
end = sv.Point(x=1280, y=500)
line_zone = sv.LineZone(start=start, end=end)

# inside the per-frame callback, after tracking:
crossed_in, crossed_out = line_zone.trigger(detections)

print(line_zone.in_count, line_zone.out_count)

LineZone also exposes per-class tallies via in_count_per_class and out_count_per_class. Render the line and counts with sv.LineZoneAnnotator (or LineZoneAnnotatorMulticlass for per-class display).


8. Detect Small Objects (Inference Slicing)

Small objects in high-resolution images are easy for a model to miss. InferenceSlicer applies the SAHI technique: it cuts the image into overlapping tiles, runs your model on each tile, and merges the results.

import cv2
import numpy as np
import supervision as sv
from ultralytics import YOLO

model = YOLO("yolov8x.pt")
image = cv2.imread("high_res.jpg")

def callback(image_slice: np.ndarray) -> sv.Detections:
    result = model(image_slice)[0]
    return sv.Detections.from_ultralytics(result)

slicer = sv.InferenceSlicer(callback=callback)
detections = slicer(image)
Parameter Default Meaning
slice_wh 640 Tile size (w, h); an int sets both
overlap_wh 100 Overlap between tiles in pixels
overlap_filter NON_MAX_SUPPRESSION How to merge overlaps: NON_MAX_SUPPRESSION, NON_MAX_MERGE, or NONE
iou_threshold 0.5 IoU used when filtering merged overlaps
thread_workers 1 Parallel tiles (see caution below)
compact_masks False Keep masks run-length encoded to avoid OOM on huge images

The same slicer works for segmentation — just return masks from your callback and use MaskAnnotator to draw them.

Warning

overlap_wh is measured in pixels, not as a percentage. Increase it when objects are large relative to the tile or often land on tile borders; decrease it for speed.

Caution

When using oriented bounding boxes (OBB), Supervision automatically falls back to sequential slice processing even if thread_workers > 1, because many OBB backends are not thread-safe. You will see a one-time warning when this happens.


9. Process Datasets

sv.DetectionDataset loads, converts, splits, merges, and saves object-detection datasets in YOLO, COCO, and Pascal VOC formats.

Load

COCO

ds = sv.DetectionDataset.from_coco(
    images_directory_path="dataset/train",
    annotations_path="dataset/train/_annotations.coco.json",
)

YOLO

ds = sv.DetectionDataset.from_yolo(
    images_directory_path="dataset/train/images",
    annotations_directory_path="dataset/train/labels",
    data_yaml_path="dataset/data.yaml",
)

Pascal VOC

ds = sv.DetectionDataset.from_pascal_voc(
    images_directory_path="dataset/train/images",
    annotations_directory_path="dataset/train/labels",
)

Iterate (images load lazily)

for image_path, image, annotations in ds:
    ...  # annotations is a Detections object

print(ds.classes)   # ['person', 'bicycle', 'car', ...]
print(len(ds))

Split, merge, and convert

# Split — returns exactly TWO datasets
train_ds, test_ds = ds.split(split_ratio=0.8, shuffle=True)

# Merge several into one
combined = sv.DetectionDataset.merge([ds_a, ds_b, ds_c])

# Convert format by loading one and saving as another
sv.DetectionDataset.from_yolo(...).as_pascal_voc(
    images_directory_path="out/images",
    annotations_directory_path="out/labels",
)

Export with ds.as_coco(...), ds.as_yolo(...), or ds.as_pascal_voc(...).

Note

split() returns two datasets (train and test). To get a validation set as well, split one of the results again, e.g. valid_ds, test_ds = test_ds.split(split_ratio=0.5).

Tip

Supervision has no built-in augmentation pipeline. Pair it with Albumentations: feed annotations.xyxy as pascal_voc-format boxes, then rebuild the annotation with dataclasses.replace(annotations, xyxy=...).


10. Benchmark a Model

Supervision computes the standard detection metrics so you can compare models numerically, not just visually.

Mean Average Precision (mAP)

from supervision.metrics import MeanAveragePrecision, MetricTarget

map_metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
map_result = map_metric.update(predictions_list, targets_list).compute()

print(map_result)          # mAP @ 50:95, @ 50, @ 75, per class, and by object size
map_result.plot()

MetricTarget selects what to evaluate: BOXES, MASKS, or ORIENTED_BOUNDING_BOXES. mAP is reported at IoU 0.50:0.95 (the headline number), plus mAP@50 and mAP@75, and is broken down by small / medium / large objects.

F1, Precision, Recall, mAR

The same update(...).compute() pattern applies to F1Score, Precision, Recall, and MeanAverageRecall, all importable from supervision.metrics.

from supervision.metrics import F1Score, MetricTarget

f1_result = F1Score(metric_target=MetricTarget.BOXES) \
    .update(predictions_list, targets_list).compute()
print(f1_result)

Confusion matrix

import supervision as sv

cm = sv.ConfusionMatrix.from_detections(
    predictions=predictions_list,
    targets=targets_list,
    classes=dataset.classes,
)
cm.plot()

Tip

Benchmark on a test set the model never saw during training. Using the training or validation set produces unrealistically optimistic numbers.


11. Keypoints, Classification, and VLMs

Keypoint detection

sv.KeyPoints is the keypoint analog of Detections, with its own connectors: from_ultralytics, from_inference, from_mediapipe, from_yolo_nas, from_detectron2, from_transformers, and from_rfdetr.

import supervision as sv
from ultralytics import YOLO

model = YOLO("yolov8m-pose.pt")
results = model(image)[0]
key_points = sv.KeyPoints.from_ultralytics(results)

edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()

annotated = edge_annotator.annotate(image.copy(), key_points=key_points)
annotated = vertex_annotator.annotate(annotated, key_points=key_points)

To track a pose model, convert keypoints to boxes with key_points.as_detections(), then feed those into ByteTrack as usual.

Classification

sv.Classifications wraps whole-image classifier output, with connectors from_clip, from_ultralytics, and from_timm, plus get_top_k(k) to retrieve the highest-scoring classes.

Vision-language models (VLMs)

Parse bounding boxes out of VLM text/JSON output with Detections.from_vlm:

import supervision as sv

paligemma_result = "<loc0256><loc0256><loc0768><loc0768> cat"
detections = sv.Detections.from_vlm(
    sv.VLM.PALIGEMMA,
    paligemma_result,
    resolution_wh=(1000, 1000),
    classes=["cat", "dog"],
)

Supported sv.VLM values: PALIGEMMA, FLORENCE_2, QWEN_2_5_VL, QWEN_3_VL, GOOGLE_GEMINI_2_0, GOOGLE_GEMINI_2_5, MOONDREAM, DEEPSEEK_VL_2.

Note

The older sv.LMM enum and Detections.from_lmm are deprecated (removal planned for supervision-0.31.0). Use sv.VLM and Detections.from_vlm instead.


12. Save and Export Detections

Stream detections to CSV or JSON for offline analysis. Both sinks are context managers — open once, append per frame, and the file is finalized on exit.

CSV

with sv.CSVSink("output.csv") as sink:
    for frame_index, frame in enumerate(sv.get_video_frames_generator("video.mp4")):
        results = model(frame)[0]
        detections = sv.Detections.from_ultralytics(results)
        sink.append(detections, {"frame_index": frame_index})

JSON

with sv.JSONSink("output.json") as sink:
    for frame_index, frame in enumerate(sv.get_video_frames_generator("video.mp4")):
        results = model(frame)[0]
        detections = sv.Detections.from_ultralytics(results)
        sink.append(detections, {"frame_index": frame_index})

The output includes box coordinates, class_id, confidence, tracker_id, class_name, plus any keys you pass in the second custom_data dictionary. Filter before appending to export only what you need:

sink.append(detections[detections.confidence > 0.7], {})

13. Working with Images and Video

Supervision bundles the file and frame utilities most CV pipelines need.

Helper Purpose
sv.VideoInfo.from_video_path(path) Read width, height, fps, frame count
sv.get_video_frames_generator(path) Iterate frames lazily
sv.process_video(source_path, target_path, callback) Run a callback over a whole video and write the result
sv.VideoSink(path, video_info) Context manager to write frames
sv.FPSMonitor() Measure real-time throughput (.fps)
sv.crop_image(image, xyxy) Crop a region
sv.resize_image / sv.letterbox_image / sv.scale_image Resize helpers
sv.plot_image(image) Show an image in a notebook
sv.plot_images_grid(images, grid_size=(r, c)) Show a grid of images

Sample assets for tutorials are available without extra installs:

from supervision.assets import download_assets, VideoAssets

download_assets(VideoAssets.PEOPLE_WALKING)

14. Colors

sv.Color and sv.ColorPalette control every annotator's appearance.

red = sv.Color.RED                       # constants: WHITE, BLACK, GREY, RED, GREEN,
purple = sv.Color.from_hex("#A351FB")    #            BLUE, YELLOW, ROBOFLOW
purple.as_bgr()                          # (251, 81, 163)  — OpenCV order

palette = sv.ColorPalette.DEFAULT        # also ROBOFLOW, LEGACY
palette = sv.ColorPalette.from_hex(["#ff0000", "#00ff00", "#0000ff"])
palette = sv.ColorPalette.from_matplotlib("viridis", 10)
palette.by_idx(3)                        # the 4th color

Caution

Older code used method-style colors such as sv.Color.white() and sv.ColorPalette.default(). These were removed in supervision-0.22.0. Use the constants instead: sv.Color.WHITE, sv.ColorPalette.DEFAULT.


15. Troubleshooting

Error: Detections confidence must be provided for tracking.

Cause: You passed a Detections object with confidence=None into ByteTrack.update_with_detections(). Trackers need confidence scores to associate objects.

Solution: Use a model output that includes confidence (all detection connectors do) and do not strip the confidence array before tracking.

Prevention: Track before any filtering step that might drop confidence.

Error: Triggering anchors cannot be empty.

Cause: You constructed PolygonZone(..., triggering_anchors=()) with an empty iterable.

Solution: Provide at least one sv.Position, e.g. triggering_anchors=(sv.Position.BOTTOM_CENTER,).

Warning: Smoothing skipped. DetectionsSmoother requires tracker_id.

Cause: DetectionsSmoother.update_with_detections() received detections without tracker_id.

Solution: Run a tracker first; the smoother averages boxes per track ID.

Prevention: Order your pipeline as detect → track → smooth → annotate.

Warning: detections have coordinates outside the slice bounds

Cause: Inside an InferenceSlicer callback, your model ran on the full image instead of the image_slice argument it was given.

Solution: Make the callback run inference on its image_slice parameter only, and return detections in slice-local coordinates — Supervision shifts them back to full- image space for you.

TypeError/unexpected keyword argument 'frame_resolution_wh'

Cause: Following an old tutorial that calls PolygonZone(polygon=..., frame_resolution_wh=...). That parameter was removed in supervision-0.24.0.

Solution: Drop it — sv.PolygonZone(polygon=polygon) is all you need now.

Masks look empty after DetectionDataset.as_coco()

Cause: Known limitation tracked in issue #2285 — segmentation masks may not be written to COCO output in some versions.

Solution: Verify your installed version against the changelog and keep masks in memory (detections.mask) as a fallback until your version includes the fix.

AttributeError: ... has no attribute 'keypoint' / deprecation warnings

Cause: Importing from the old supervision.keypoint module.

Solution: Use supervision.key_points (with an underscore). The old spelling is deprecated and slated for removal in supervision-0.30.0.

Tip

To silence Supervision's deprecation warnings in a known-good pipeline, set the environment variable SUPERVISON_DEPRECATION_WARNING=0 before importing the library. (Note the original spelling of the variable.)


16. Frequently Asked Questions

Q: Does Supervision run my model for me? No. Supervision is model-agnostic and never performs inference. You run any model you like and pass its output to a Detections.from_* connector.

Q: Which models are supported? Object detection, segmentation, and keypoint outputs from Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers, SAM and SAM 3, Detectron2, MMDetection, YOLO-NAS, YOLOv5, DeepSparse, PaddleDetection, TensorFlow Hub, NCNN, EasyOCR, Azure AI Vision, and VLMs (Florence-2, PaliGemma, Qwen-VL, Gemini, Moondream, DeepSeek-VL2).

Q: How do I filter detections by class? Use boolean indexing: detections[detections.class_id == 0]. Combine conditions with & and |.

Q: How do I track objects across frames? Call tracker.update_with_detections(detections) each frame with sv.ByteTrack (note it is being superseded by the external trackers package). The tracker fills in detections.tracker_id.

Q: How do I count objects crossing a line? Use sv.LineZone with a start and end sv.Point. trigger() returns (crossed_in, crossed_out). It requires tracker_id, so track first.

Q: How do I count objects inside a region? Use sv.PolygonZone. trigger() returns a boolean mask, and zone.current_count gives the live count.

Q: How do I improve detection of tiny objects? Use sv.InferenceSlicer to run your model on overlapping tiles and merge the results.

Q: What dataset formats can I load and save? YOLO, COCO JSON, and Pascal VOC via DetectionDataset.from_* and .as_* methods.

Q: How do I compute mAP? MeanAveragePrecision().update(predictions, targets).compute() from supervision.metrics. It reports mAP@50:95, @50, @75, per class, and by object size.

Q: Can I use my own colors and fonts? Yes. Pass sv.Color/sv.ColorPalette to any annotator, and use RichLabelAnnotator for custom (including non-Latin) fonts.

Q: Is Supervision free? Yes. It is open source under the MIT license.

Q: Why am I seeing a ByteTrack deprecation warning? The built-in ByteTrack is being phased out in favor of ByteTrackTracker from the trackers package (pip install trackers); the update method there is update().

Q: Where can I get help? The documentation, the Discord community, and GitHub issues.


17. Quick Reference

The universal pipeline

detections = sv.Detections.from_<model>(result)   # 1. connect
detections = detections[detections.confidence > 0.5]   # 2. filter
detections = tracker.update_with_detections(detections)   # 3. track (video)
mask = zone.trigger(detections)                    # 4. zone count
annotated = annotator.annotate(scene, detections)  # 5. visualize

Position anchors

CENTER, CENTER_LEFT, CENTER_RIGHT, TOP_CENTER, TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT, CENTER_OF_MASS.

Color lookup strategies

ColorLookup.INDEX (by order), ColorLookup.CLASS (by class — default), ColorLookup.TRACK (by tracker ID — stable per object across frames).

Key imports

import supervision as sv
from supervision.metrics import MeanAveragePrecision, F1Score, MetricTarget
from supervision.assets import download_assets, VideoAssets