部分示例需额外安装可选依赖,如 pip install pillow rfdetr;使用 Inference 连接器需提供 Roboflow API KEY;数据集示例依赖 roboflow 包下载数据
supervision
roboflowMIT活跃维护一套可复用的计算机视觉工具库,提供目标检测、实例分割、分类等任务的标注处理、指标计算与可视化组件,帮开发者省去重复造轮子的时间。
We write your reusable computer vision tools. 💜
pip install supervisionREADME 未说明,仅要求 Python>=3.10 环境
模型无关的计算机视觉工具库,提供检测结果处理、标注可视化和数据集转换的通用积木
一套可复用的计算机视觉工具库,提供目标检测、实例分割、分类等任务的标注处理、指标计算与可视化组件,帮开发者省去重复造轮子的时间。
核心能力
- 用 sv.Detections 统一封装各框架的检测结果
- 提供 BoxAnnotator 等可组合的标注器做可视化
- 支持 COCO、YOLO、Pascal VOC 数据集加载与保存
- 可对数据集做切分、合并与格式互转
- 内置 Ultralytics、Transformers、MMDetection 等连接器
容易踩的坑
- 0.31.5supervision-0.31.5最新正式版2026-11-05 · 2026-11-05 18:35 UTC
v0.31.5: Line counts through occlusion, the exact clipper for oriented boxes, and right-to-left labels
Right-to-left labels, line counting that survives occlusion, and a batch of edge-case fixes across annotators, exports and the NumPy fallback.
- LineZone counts objects that are hidden for a few frames while they cross the line.
- Arabic and Hebrew labels render correctly with the new
rtlextra. - Oriented-box IoU, NMS and metrics now use the exact clipper on OpenCV installs.
- Annotating a Pillow image keeps its transparency and untouched pixels.
- Heat maps and ellipse halos now work on grayscale scenes.
It's a drop-in upgrade, but check the Migration guide if you count line crossings, score-oriented boxes on OpenCV, or compare stored outputs.
✨ Spotlights / highlights
Right-to-left labels with the new
rtlextrasv.RichLabelAnnotatornow draws Arabic and Hebrew labels correctly on RGB and RGBA images when the newrtlextra is installed. Pillow only joins Arabic letters and orders right-to-left text when it's built with Raqm, and most Windows installs and many containers lack it. There,"سيارة 0.92"came out as isolated letters in reverse order. Lines with Arabic or Hebrew are now shaped in the label's font, using fallback Arabic and Hebrew fonts fromkhattfor missing glyphs, and right-aligned in the background box. Other image modes fall back to Pillow, with a warning that suggests RGB or RGBA when Raqm is missing. Without the extra, a one-time warning names it. (#2864)# pip install "supervision[rtl]" import supervision as sv label_annotator = sv.RichLabelAnnotator(font_path="NotoNaskhArabic-Regular.ttf") annotated = label_annotator.annotate( scene=image, detections=detections, labels=["سيارة 0.92"] )LineZonecounts objects occluded while crossingIf a tracker disappears for a few frames while crossing the line, it's still counted. By default,
sv.LineZonedrops a tracker's stored side aftermax(30, minimum_crossing_threshold + 1)consecutive absent frames. It used to drop it aftermax(2, minimum_crossing_threshold + 1), which is 2 at the default threshold. The newmax_absent_framesparameter sets this. Counts can rise against 0.31.4 on the same input. (#2873)import numpy as np import supervision as sv line = sv.LineZone(start=sv.Point(0, 50), end=sv.Point(100, 50)) def detection(y): return sv.Detections( xyxy=np.array([[40.0, y - 10, 60.0, y]]), tracker_id=np.array([1]) ) line.trigger(detection(40)) # above the line for _ in range(5): # occluded for five frames line.trigger(sv.Detections.empty()) line.trigger(detection(80)) # reappears below the line line.in_count, line.out_count # (0, 1) (0.31.4: (0, 0)) # Restore the old retention: sv.LineZone(start=sv.Point(0, 50), end=sv.Point(100, 50), max_absent_frames=2)The exact clipper for oriented boxes on OpenCV installs
sv.oriented_box_iou_batch, OBB NMS and OBB metrics now use the same convex clipper on OpenCV installs that the NumPy fallback uses. With OpenCV, rotated boxes with nearly collinear overlapping edges, and boxes with both sides far below one coordinate unit, could get an IoU of 0 or 1. The clipper is roughly 10x slower per candidate pair than the OpenCV call, so crowded scenes can take seconds. Oriented-box precision, recall, F1, and mean average recall also keep corner precision at large coordinate origins. (#2882, #2887)import numpy as np import supervision as sv def rotated(width, height, degrees, center=(200.0, 200.0)): t = np.deg2rad(degrees) u = np.array([np.cos(t), np.sin(t)]) * width / 2 v = np.array([-np.sin(t), np.cos(t)]) * height / 2 c = np.array(center) return np.array([[c - u - v, c + u - v, c + u + v, c - u + v]]) t = np.deg2rad(10) a = rotated(100, 40, 10) b = a + np.array([np.cos(t), np.sin(t)]) * 50 # true IoU is 0 - 0.31.4supervision-0.31.42026-11-03 · 2026-11-03 16:28 UTC
查看更新说明
v0.31.4 — Stricter dataset export, COCO-exact recall buckets, and a closer NumPy fallback
Fourteen bug fixes: stricter dataset export, COCO-exact recall buckets, sturdier VLM parsing, and a NumPy fallback closer to OpenCV.
- CreateML and Pascal VOC export raise a clear
ValueErrorfor aclass_idoutsideclasses. DetectionDataset.mergekeeps annotations that have no class IDs instead of raising.- MeanAverageRecall counts boundary-area objects in both COCO size buckets, like
MeanAveragePrecision. - Qwen and PaliGemma parsing keep valid boxes and class labels beside malformed ones.
- Without OpenCV, image reads, gray conversion, drawing colors and keyword parameters match OpenCV.
Drop-in upgrade; see the Migration guide if you export out-of-range class IDs or compare mAR values or fallback pixels against stored references.
✨ Spotlights / highlights
Dataset export rejects out-of-range class IDs
detections_to_createml_annotationsanddetections_to_pascal_vocnow raiseValueErrorfor aclass_idoutsideclasses, asdetections_to_labelme_shapesalready does. A negative id was exported under the last class name, and an id past the end raisedIndexError. (#2859)import numpy as np import supervision as sv from supervision.dataset.formats.createml import detections_to_createml_annotations detections = sv.Detections( xyxy=np.array([[10.0, 10.0, 50.0, 50.0]]), class_id=np.array([-1]) ) detections_to_createml_annotations(detections, classes=["cat", "dog"]) # ValueError: class_id -1 at detection index 0 is out of range for classes list of length 2. # 0.31.3: exported with the label "dog"DetectionDataset.mergekeeps annotations without class IDsMerging datasets used to raise
ValueErrorwhen some annotations had noclass_id. They are now kept as they are while labeled annotations are remapped. (#2858)import numpy as np import supervision as sv labeled = sv.DetectionDataset( classes=["a"], images=["x.jpg"], annotations={ "x.jpg": sv.Detections(xyxy=np.array([[0.0, 0, 5, 5]]), class_id=np.array([0])) }, ) unlabeled = sv.DetectionDataset( classes=["b"], images=["y.jpg"], annotations={"y.jpg": sv.Detections(xyxy=np.array([[0.0, 0, 5, 5]]))}, ) merged = sv.DetectionDataset.merge([labeled, unlabeled]) merged.classes # ['a', 'b'] (0.31.3: ValueError)MeanAverageRecallsize buckets match COCOAn object whose area is exactly
32²or96²now counts in both neighbouring size buckets, the inclusive ranges pycocotools andMeanAveragePrecisionuse. It used to land in only one, so mAR and mAP disagreed on the small, medium and large results. (#2848)import numpy as np import supervision as sv from supervision.metrics import MeanAverageRecall box = np.array([[0.0, 0.0, 32.0, 32.0]]) # area is exactly 32² target = sv.Detections(xyxy=box, class_id=np.array([0])) prediction = sv.Detections(xyxy=box, class_id=np.array([0]), confidence=np.array([0.9])) result = MeanAverageRecall().update([prediction], [target]).compute() result.small_objects.mAR_at_100, result.medium_objects.mAR_at_100 # (1.0, 1.0) (0.31.3: (0.0, 1.0))🔄 Migration guide
No public symbol was removed or renamed, and nothing is deprecated. A few fixes change what existing code returns or raises:
- New error: CreateML and Pascal VOC export raise
ValueErrorfor aclass_idoutsideclasses. Make sure every exported id indexes into yourclasseslist; filter or remap ids such as-1first. (#2859) - Different numbers:
MeanAverageRecallsmall, medium and large results can change for datasets with objects of area exactly32²or96². (#2848) - Different pixels without OpenCV: drawing colors saturate instead of wrapping,
uint16gray conversion and 16-bit grayscale reads follow OpenCV, andIMREAD_GRAYSCALEreturns a two-dimension
- CreateML and Pascal VOC export raise a clear
- 0.31.3supervision-0.31.32026-10-28 · 2026-10-28 08:39 UTC
查看更新说明
v0.31.3 — Grayscale annotators, OpenCV-exact fallbacks, and merged YOLO polygons
Grayscale scenes work with more annotators, the pure NumPy fallback matches OpenCV pixel for pixel, and YOLO export handles multi-part masks.
- YOLO export merges multi-part masks into one polygon and skips crowd annotations, with flags for the old output.
- Background overlay and comparison annotators draw on grayscale scenes.
- Without OpenCV, resize, blur, blending, drawing and connected components give the same pixels as OpenCV.
- Invalid input fails early:
ImageSink, the video frame generator and depth arrays now raise clear errors. - Short hex colors such as
"#f0f"work in annotators.
Drop-in upgrade unless you export YOLO labels: the default output changes, see the Migration guide.
✨ Spotlights / highlights
YOLO export merges multi-part masks and skips crowd annotations
DetectionDataset.as_yolonow omits detections whoseiscrowdflag is set and writes a mask with several disconnected parts as one merged polygon line instead of one line per part. Both are on by default. The merge is done by the newsv.merge_multi_segment, which joins the parts through zero-width seams at their nearest vertices. (#2786)import supervision as sv dataset = sv.DetectionDataset(...) dataset.as_yolo( images_directory_path="images", annotations_directory_path="labels", data_yaml_path="data.yaml", ) # 0.31.3: crowd skipped, one merged polygon line per mask dataset.as_yolo( images_directory_path="images", annotations_directory_path="labels", data_yaml_path="data.yaml", ignore_crowd=False, merge_segments=False, ) # the 0.31.2 outputsv.merge_multi_segmentNew public function. Pass it the polygon parts of one mask and get back a single polygon. (#2786)
import numpy as np import supervision as sv a = np.array([[0, 0], [10, 0], [10, 10], [0, 10]]) b = np.array([[30, 30], [40, 30], [40, 40], [30, 40]]) sv.merge_multi_segment([a, b]).shape # (10, 2)Annotators on grayscale scenes
BackgroundOverlayAnnotatorandComparisonAnnotatornow draw on scenes shaped(H, W)or(H, W, 1), or given as a Pillow"L"image, instead of raisingValueError. Short hex colors such as"#f0f"now work in annotators andsv.hex_to_rgba. (#2832, #2803, #2801)import numpy as np import supervision as sv scene = np.zeros((100, 100), dtype=np.uint8) detections = sv.Detections( xyxy=np.array([[20, 20, 60, 60]], dtype=float), class_id=np.array([0]) ) sv.BackgroundOverlayAnnotator().annotate(scene.copy(), detections).shape # (100, 100) (0.31.2: ValueError)The NumPy fallback matches OpenCV pixel for pixel
Without OpenCV installed,
resize(INTER_LINEARonuint8),blur,addWeighted, thin lines, circles, filled polygons that leave the canvas,connectedComponentsandmeannow give the same pixels as OpenCV.BlurAnnotator,HaloAnnotator,HeatMapAnnotator,PixelateAnnotator, the blending annotators,sv.resize_image,sv.letterbox_imageandPolygonZonemasks are affected. (#2833, #2836, #2811, #2808, #2810, #2812, #2820)Bad input fails early
sv.ImageSink(overwrite=False)raisesFileExistsErrorinstead of replacing an existing image,sv.get_video_frames_generatorrejects a stride below 1, andDepthMap.from_ultralyticsrejects unwrapped integer arrays. (#2800, #2819, #2795)import supervision as sv for frame in sv.get_video_frames_generator("video.mp4", stride=0): ... # ValueError: stride must be >= 1, got 0🔄 Migration guide
One default behavior changes: YOLO export. No public symbol was removed or renamed in this release, and nothing is deprecated.
YOLO export defaults affect
sv.DetectionDataset.as_yolo, andsave_yolo_annotationsanddetections_to_yolo_annotationsin `supervision.dataset.formats.yol - 0.31.2supervision-0.31.22026-10-24 · 2026-10-24 11:47 UTC
查看更新说明
v0.31.2 — Pascal VOC boxes that match the devkit
A bug-fix release: Pascal VOC boxes now follow the devkit convention, and a batch of crashes on edge-case inputs is gone.
- Pascal VOC export and import use the devkit's box indices, so Detectron2 and other readers see the boxes you wrote.
- Gemini 2.5 and 3.5 masks survive boxes that leave the 0-1000 range instead of failing the whole response.
- Crop and icon annotators draw on grayscale scenes.
- Half-precision box centers stay finite instead of turning into
inf. - JSON sinks, dataset exports and the video reader stop losing data when something goes wrong.
Drop-in upgrade, with one catch: box-only Pascal VOC objects written by earlier versions now load one pixel larger on the right and bottom edges. The migration guide below shows how to fix them.
✨ Spotlights / highlights
Pascal VOC boxes follow the devkit
DetectionDataset.as_pascal_vocandfrom_pascal_vocnow treat<bndbox>indices as 1-based and inclusive, shifting onlyxminandyminby one, which is what Detectron2 and other devkit readers expect. Export also rounds corners to the nearest pixel instead of truncating them, so a YOLO box thatfrom_yololoads with float noise no longer grows a pixel. Box-only objects written by 0.31.1 and earlier carry an extra +1 inxmaxandymax; objects exported from masks already used the devkit maxima. (#2748, #2780)# `dataset` holds one box [10, 20, 40, 60] dataset.as_pascal_voc( images_directory_path="images", annotations_directory_path="annotations" ) # <bndbox>: xmin=11 ymin=21 xmax=40 ymax=60 (0.31.1: xmax=41 ymax=61) # a YOLO box loaded as [0, 0, 37.0000001, 29.0000001]: 1 1 37 29 (0.31.1: 1 1 38 30)Gemini masks survive boxes outside the 0-1000 range
Detections.from_vlmwithVLM.GOOGLE_GEMINI_2_5orVLM.GOOGLE_GEMINI_3_5raisedValueErroras soon as abox_2dcoordinate went above 1000 or below 0, even by one, and you lost every detection in the response. The mask is now cropped to the part of its box inside the image, a box wholly outside gets an all-false mask, and boxes inside the image produce the same masks as before. (#2793)import supervision as sv # one item: {"box_2d": [500, 500, 1001, 1001], "label": "cat", "mask": "data:image/png;base64,..."} detections = sv.Detections.from_vlm( sv.VLM.GOOGLE_GEMINI_3_5, result, resolution_wh=(1000, 800) ) detections.mask.shape, int(detections.mask.sum()) # ((1, 800, 1000), 200000) # 0.31.1: ValueError: could not broadcast input array from shape (400,501) into shape (400,500)Crop and icon annotators on grayscale scenes
CropAnnotatorandIconAnnotatorused to raiseIndexErrororValueErroron scenes shaped(H, W)or(H, W, 1), or given as a Pillow"L"image. Crops now keep the scene's channel layout, and icons are drawn as their gray luminance, blended by their alpha channel. (#2788)import numpy as np import supervision as sv scene = np.zeros((100, 100), dtype=np.uint8) scene[20:60, 20:60] = 200 detections = sv.Detections( xyxy=np.array([[20, 20, 60, 60]], dtype=float), class_id=np.array([0]) ) sv.CropAnnotator().annotate(scene.copy(), detections).shape # (100, 100) (0.31.1: IndexError: tuple index out of range)Half-precision boxes that stay finite
sv.scale_boxesandDetections.get_anchors_coordinatesnow compute box centers without overflowingfloat16: a box from 40000 to 60000 used to report aninfcenter.DetectionsSmootheralso compares oriented-box corner distances infloat64, which stopsfloat16and narrow integer coordinates from overflowing; integer coordinates beyond2**53still lose low-order pixels in thefloat64average. (#2787, #2785)import numpy as np import supervision as sv detections = sv.Detections( xyxy=np.array([[40000, 40000, 60000, 60000]], dtype=np.float16) ) detection - 0.31.1supervision-0.31.12026-10-20 · 2026-10-20 18:13 UTC
查看更新说明
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.
MeanAverageRecallskips crowd regions and matches predictions in confidence order, likepycocotools.- COCO segmentations loaded without an
areafield no longer make mAP return-1. float16boxes keep finite areas, and mAP andwith_nmmstop 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.MeanAverageRecallused to count COCO crowd regions as missed objects and to pair predictions with the highest-IoU target first. It now leaves out targets withdata["iscrowd"]ordata["ignore"]set, the same ruleMeanAveragePrecisionuses. 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.0Half-precision boxes that stay finite
A 256×256 box in
float16has an area of 65,536, which is pastfloat16's maximum, soDetections.box_areareturnedinfand area filters dropped it. Box areas offloat16detections are now computed and returned infloat32, andMeanAveragePrecisionandwith_nmmno longer overflow onfloat16or narrow integer coordinates either. COCO segmentations loaded with masks but without anareafield 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.MaskAnnotatorandsv.HaloAnnotatorraisedValueErroron 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.VertexAnnotatorand 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 ce
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
notebooks | inference | autodistill | maestro
👋 Hello
We are your essential toolkit for computer vision. From data loading to real-time zone counting, we provide the building blocks so you can focus on building applications around your models. 🤝
💻 Install
Pip install the supervision package in a Python>=3.10 environment.
pip install supervision
Read more about conda, mamba, and installing from source in our guide.
🔥 Quickstart
Models
Supervision was designed to be model agnostic. Just plug in any classification, detection, or segmentation model. For your convenience, we have created connectors for the most popular libraries like Ultralytics, Transformers, MMDetection, or Inference. Other integrations, like rfdetr, already return sv.Detections directly.
Install the optional dependencies for this example with pip install pillow rfdetr.
import supervision as sv
from PIL import Image
from rfdetr import RFDETRSmall
image = Image.open("path/to/image.jpg")
model = RFDETRSmall()
detections = model.predict(image, threshold=0.5)
len(detections)
# 5
-
inference
Running with Inference requires a Roboflow API KEY.
import supervision as sv from PIL import Image from inference import get_model image = Image.open("path/to/image.jpg") model = get_model(model_id="rfdetr-small", api_key="ROBOFLOW_API_KEY") result = model.infer(image)[0] detections = sv.Detections.from_inference(result) len(detections) # 5
Annotators
Supervision offers a wide range of highly customizable annotators, allowing you to compose the perfect visualization for your use case.
import cv2
import supervision as sv
image = cv2.imread("path/to/image.jpg")
# Assuming detections are obtained from a model
detections = sv.Detections(...)
box_annotator = sv.BoxAnnotator()
annotated_frame = box_annotator.annotate(scene=image.copy(), detections=detections)
https://github.com/roboflow/supervision/assets/26109316/691e219c-0565-4403-9218-ab5644f39bce
Datasets
Supervision provides a set of utils that allow you to load, split, merge, and save datasets in one of the supported formats.
import supervision as sv
from roboflow import Roboflow
project = Roboflow().workspace("WORKSPACE_ID").project("PROJECT_ID")
dataset = project.version("PROJECT_VERSION").download("coco")
ds = sv.DetectionDataset.from_coco(
images_directory_path=f"{dataset.location}/train",
annotations_path=f"{dataset.location}/train/_annotations.coco.json",
)
path, image, annotation = ds[0]
# loads image on demand
for path, image, annotation in ds:
# loads image on demand
pass
-
load
dataset = sv.DetectionDataset.from_yolo( images_directory_path=..., annotations_directory_path=..., data_yaml_path=..., ) dataset = sv.DetectionDataset.from_pascal_voc( images_directory_path=..., annotations_directory_path=..., ) dataset = sv.DetectionDataset.from_coco( images_directory_path=..., annotations_path=..., ) -
split
train_dataset, test_dataset = dataset.split(split_ratio=0.7) test_dataset, valid_dataset = test_dataset.split(split_ratio=0.5) len(train_dataset), len(test_dataset), len(valid_dataset) # (700, 150, 150) -
merge
ds_1 = sv.DetectionDataset(...) len(ds_1) # 100 ds_1.classes # ['dog', 'person'] ds_2 = sv.DetectionDataset(...) len(ds_2) # 200 ds_2.classes # ['cat'] ds_merged = sv.DetectionDataset.merge([ds_1, ds_2]) len(ds_merged) # 300 ds_merged.classes # ['cat', 'dog', 'person'] -
save
dataset.as_yolo( images_directory_path=..., annotations_directory_path=..., data_yaml_path=..., ) dataset.as_pascal_voc( images_directory_path=..., annotations_directory_path=..., ) dataset.as_coco( images_directory_path=..., annotations_path=..., ) -
convert
sv.DetectionDataset.from_yolo( images_directory_path=..., annotations_directory_path=..., data_yaml_path=..., ).as_pascal_voc( images_directory_path=..., annotations_directory_path=..., )
🎬 Tutorials
Want to learn how to use Supervision? Explore our how-to guides, end-to-end examples, cheatsheet, and cookbooks!
💜 Built with Supervision
Did you build something cool using supervision? Let us know!
https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-60e9c81b3900
https://github.com/roboflow/supervision/assets/26109316/3ac6982f-4943-4108-9b7f-51787ef1a69f
📚 Documentation
Visit our documentation page to learn how supervision can help you build computer vision applications faster and more reliably.
🏆 Contribution
We love your input! Please see our contributing guide to get started. Thank you 🙏 to all our contributors!