From 6461d3fbac0c4b2837e0ac94504c2f0ff62dd413 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 May 2026 19:54:33 +0200 Subject: [PATCH] =?UTF-8?q?Restructure=20annotator=20docs=20tabs=20to=20av?= =?UTF-8?q?oid=20Material=E2=80=99s=2020-tab=20limit=20(#2257)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * fix: split annotator docs tabs into categories * test: harden annotator docs regression test * docs: fix blur example assignment * docs(annotators): restructure tabs, harden regression tests * docs(annotators): remove broken oriented box preview image --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Borda <6035284+Borda@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Claude Code --- docs/detection/annotators.md | 865 +++++++++++++++++----------------- tests/annotators/test_docs.py | 148 ++++++ 2 files changed, 589 insertions(+), 424 deletions(-) create mode 100644 tests/annotators/test_docs.py diff --git a/docs/detection/annotators.md b/docs/detection/annotators.md index 90a9006c..651a6223 100644 --- a/docs/detection/annotators.md +++ b/docs/detection/annotators.md @@ -7,510 +7,527 @@ description: API reference for supervision's annotator classes — draw bounding Annotators accept detections and apply box or mask visualizations to the detections. Annotators have many available styles. -=== "Box" +=== "Outlines" - ```python - import supervision as sv + === "Box" - image = ... - detections = sv.Detections(...) + ```python + import supervision as sv - box_annotator = sv.BoxAnnotator() - annotated_frame = box_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` + image = ... + detections = sv.Detections(...) -
- - ![bounding-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/bounding-box-annotator-example-purple.png){ align=center width="800" } - -
- -=== "RoundBox" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - round_box_annotator = sv.RoundBoxAnnotator() - annotated_frame = round_box_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![round-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/round-box-annotator-example-purple.png){ align=center width="800" } - -
- -=== "BoxCorner" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - corner_annotator = sv.BoxCornerAnnotator() - annotated_frame = corner_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![box-corner-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-corner-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Color" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - color_annotator = sv.ColorAnnotator() - annotated_frame = color_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![box-mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-mask-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Circle" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - circle_annotator = sv.CircleAnnotator() - annotated_frame = circle_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![circle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/circle-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Dot" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - dot_annotator = sv.DotAnnotator() - annotated_frame = dot_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![dot-annotator-example](https://media.roboflow.com/supervision-annotator-examples/dot-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Triangle" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - triangle_annotator = sv.TriangleAnnotator() - annotated_frame = triangle_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![triangle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/triangle-annotator-example.png){ align=center width="800" } - -
- -=== "Ellipse" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - ellipse_annotator = sv.EllipseAnnotator() - annotated_frame = ellipse_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ellipse-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Halo" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - halo_annotator = sv.HaloAnnotator() - annotated_frame = halo_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![halo-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" } - -
- -=== "PercentageBar" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - percentage_bar_annotator = sv.PercentageBarAnnotator() - annotated_frame = percentage_bar_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![percentage-bar-annotator-example](https://media.roboflow.com/supervision-annotator-examples/percentage-bar-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Mask" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - mask_annotator = sv.MaskAnnotator() - annotated_frame = mask_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Polygon" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - polygon_annotator = sv.PolygonAnnotator() - annotated_frame = polygon_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` - -
- - ![polygon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/polygon-annotator-example-purple.png){ align=center width="800" } - -
- -=== "Label" - - ```python - import supervision as sv - - image = ... - detections = sv.Detections(...) - - labels = [ - f"{class_name} {confidence:.2f}" - for class_name, confidence in zip( - detections["class_name"], - detections.confidence, + box_annotator = sv.BoxAnnotator() + annotated_frame = box_annotator.annotate( + scene=image.copy(), + detections=detections, ) - ] + ``` - label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER) - annotated_frame = label_annotator.annotate( - scene=image.copy(), detections=detections, labels=labels - ) - ``` +
-
+ ![bounding-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/bounding-box-annotator-example-purple.png){ align=center width="800" } - ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" } +
-
+ === "RoundBox" -=== "RichLabel" + ```python + import supervision as sv - ```python - import supervision as sv + image = ... + detections = sv.Detections(...) - image = ... - detections = sv.Detections(...) - - labels = [ - f"{class_name} {confidence:.2f}" - for class_name, confidence in zip( - detections["class_name"], - detections.confidence, + round_box_annotator = sv.RoundBoxAnnotator() + annotated_frame = round_box_annotator.annotate( + scene=image.copy(), + detections=detections, ) - ] + ``` - rich_label_annotator = sv.RichLabelAnnotator( - font_path="TTF_FONT_PATH", - text_position=sv.Position.CENTER, - ) - annotated_frame = rich_label_annotator.annotate( - scene=image.copy(), - detections=detections, - labels=labels, - ) - ``` +
-
+ ![round-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/round-box-annotator-example-purple.png){ align=center width="800" } - ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" } +
-
+ === "BoxCorner" -=== "Icon" + ```python + import supervision as sv - ```python - import supervision as sv + image = ... + detections = sv.Detections(...) - image = ... - detections = sv.Detections(...) + corner_annotator = sv.BoxCornerAnnotator() + annotated_frame = corner_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` - icon_paths = ["" for _ in detections] +
- icon_annotator = sv.IconAnnotator() - annotated_frame = icon_annotator.annotate( - scene=image.copy(), - detections=detections, - icon_path=icon_paths, - ) - ``` + ![box-corner-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-corner-annotator-example-purple.png){ align=center width="800" } -
+
- ![icon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/icon-annotator-example.png){ align=center width="800" } + === "Circle" -
+ ```python + import supervision as sv - + image = ... + detections = sv.Detections(...) -=== "Blur" + ellipse_annotator = sv.EllipseAnnotator() + annotated_frame = ellipse_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` - ```python - import supervision as sv +
- image = ... - detections = sv.Detections(...) + ![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ellipse-annotator-example-purple.png){ align=center width="800" } - blur_annotator = sv.BlurAnnotator() - annotated_frame = (blur_annotator.annotate(scene=image.copy(), detections=detections),) - ``` +
-
+ === "Polygon" - ![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-purple.png){ align=center width="800" } + ```python + import supervision as sv -
+ image = ... + detections = sv.Detections(...) -=== "Pixelate" + polygon_annotator = sv.PolygonAnnotator() + annotated_frame = polygon_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` - ```python - import supervision as sv +
- image = ... - detections = sv.Detections(...) + ![polygon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/polygon-annotator-example-purple.png){ align=center width="800" } - pixelate_annotator = sv.PixelateAnnotator() - annotated_frame = pixelate_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` +
-
+=== "Shading" - ![pixelate-annotator-example](https://media.roboflow.com/supervision-annotator-examples/pixelate-annotator-example-10.png){ align=center width="800" } + === "Color" -
+ ```python + import supervision as sv -=== "Trace" + image = ... + detections = sv.Detections(...) - ```python - import supervision as sv - from ultralytics import YOLO + color_annotator = sv.ColorAnnotator() + annotated_frame = color_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` - model = YOLO("yolov8x.pt") +
- trace_annotator = sv.TraceAnnotator() + ![box-mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-mask-annotator-example-purple.png){ align=center width="800" } - video_info = sv.VideoInfo.from_video_path(video_path="...") - frames_generator = sv.get_video_frames_generator(source_path="...") - tracker = sv.ByteTrack() +
- with sv.VideoSink(target_path="...", video_info=video_info) as sink: - for frame in frames_generator: - result = model(frame)[0] - detections = sv.Detections.from_ultralytics(result) - detections = tracker.update_with_detections(detections) - annotated_frame = trace_annotator.annotate( - scene=frame.copy(), - detections=detections, + === "Halo" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + halo_annotator = sv.HaloAnnotator() + annotated_frame = halo_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` + +
+ + ![halo-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" } + +
+ + === "Mask" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + mask_annotator = sv.MaskAnnotator() + annotated_frame = mask_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` + +
+ + ![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example-purple.png){ align=center width="800" } + +
+ +=== "Markers" + + === "Dot" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + dot_annotator = sv.DotAnnotator() + annotated_frame = dot_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` + +
+ + ![dot-annotator-example](https://media.roboflow.com/supervision-annotator-examples/dot-annotator-example-purple.png){ align=center width="800" } + +
+ + === "Triangle" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + triangle_annotator = sv.TriangleAnnotator() + annotated_frame = triangle_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` + +
+ + ![triangle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/triangle-annotator-example.png){ align=center width="800" } + +
+ +=== "Labels" + + === "Label" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + labels = [ + f"{class_name} {confidence:.2f}" + for class_name, confidence in zip( + detections["class_name"], + detections.confidence, ) - sink.write_frame(frame=annotated_frame) - ``` + ] -
+ label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER) + annotated_frame = label_annotator.annotate( + scene=image.copy(), detections=detections, labels=labels + ) + ``` - ![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example-purple.png){ align=center width="800" } +
-
+ ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" } -=== "HeatMap" +
- ```python - import supervision as sv - from ultralytics import YOLO + === "RichLabel" - model = YOLO("yolov8x.pt") + ```python + import supervision as sv - heat_map_annotator = sv.HeatMapAnnotator() + image = ... + detections = sv.Detections(...) - video_info = sv.VideoInfo.from_video_path(video_path="...") - frames_generator = sv.get_video_frames_generator(source_path="...") - - with sv.VideoSink(target_path="...", video_info=video_info) as sink: - for frame in frames_generator: - result = model(frame)[0] - detections = sv.Detections.from_ultralytics(result) - annotated_frame = heat_map_annotator.annotate( - scene=frame.copy(), - detections=detections, + labels = [ + f"{class_name} {confidence:.2f}" + for class_name, confidence in zip( + detections["class_name"], + detections.confidence, ) - sink.write_frame(frame=annotated_frame) - ``` + ] -
+ rich_label_annotator = sv.RichLabelAnnotator( + font_path="TTF_FONT_PATH", + text_position=sv.Position.CENTER, + ) + annotated_frame = rich_label_annotator.annotate( + scene=image.copy(), + detections=detections, + labels=labels, + ) + ``` - ![heat-map-annotator-example](https://media.roboflow.com/supervision-annotator-examples/heat-map-annotator-example-purple.png){ align=center width="800" } +
-
+ ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" } -=== "Background Color" +
- ```python - import supervision as sv +=== "Transformative" - image = ... - detections = sv.Detections(...) + === "Blur" - background_overlay_annotator = sv.BackgroundOverlayAnnotator() - annotated_frame = background_overlay_annotator.annotate( - scene=image.copy(), - detections=detections, - ) - ``` + ```python + import supervision as sv -
+ image = ... + detections = sv.Detections(...) - ![background-overlay-annotator-example](https://media.roboflow.com/supervision-annotator-examples/background-color-annotator-example-purple.png){ align=center width="800" } + blur_annotator = sv.BlurAnnotator() + annotated_frame = blur_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` -
+
-=== "Comparison" + ![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-purple.png){ align=center width="800" } - ```python - import supervision as sv +
- image = ... - detections_1 = sv.Detections(...) - detections_2 = sv.Detections(...) + === "Pixelate" - comparison_annotator = sv.ComparisonAnnotator() - annotated_frame = comparison_annotator.annotate( - scene=image.copy(), - detections_1=detections_1, - detections_2=detections_2, - ) - ``` + ```python + import supervision as sv -
+ image = ... + detections = sv.Detections(...) - ![comparison-annotator-example](https://media.roboflow.com/supervision-annotator-examples/comparison-annotator-example.png){ align=center width="800" } + pixelate_annotator = sv.PixelateAnnotator() + annotated_frame = pixelate_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` -
+
+ + ![pixelate-annotator-example](https://media.roboflow.com/supervision-annotator-examples/pixelate-annotator-example-10.png){ align=center width="800" } + +
+ + + +=== "Tracking & Aggregation" + + === "Trace" + + ```python + import supervision as sv + from ultralytics import YOLO + + model = YOLO("yolov8x.pt") + + trace_annotator = sv.TraceAnnotator() + + video_info = sv.VideoInfo.from_video_path(video_path="...") + frames_generator = sv.get_video_frames_generator(source_path="...") + tracker = sv.ByteTrack() + + with sv.VideoSink(target_path="...", video_info=video_info) as sink: + for frame in frames_generator: + result = model(frame)[0] + detections = sv.Detections.from_ultralytics(result) + detections = tracker.update_with_detections(detections) + annotated_frame = trace_annotator.annotate( + scene=frame.copy(), + detections=detections, + ) + sink.write_frame(frame=annotated_frame) + ``` + +
+ + ![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example-purple.png){ align=center width="800" } + +
+ + === "HeatMap" + + ```python + import supervision as sv + from ultralytics import YOLO + + model = YOLO("yolov8x.pt") + + heat_map_annotator = sv.HeatMapAnnotator() + + video_info = sv.VideoInfo.from_video_path(video_path="...") + frames_generator = sv.get_video_frames_generator(source_path="...") + + with sv.VideoSink(target_path="...", video_info=video_info) as sink: + for frame in frames_generator: + result = model(frame)[0] + detections = sv.Detections.from_ultralytics(result) + annotated_frame = heat_map_annotator.annotate( + scene=frame.copy(), + detections=detections, + ) + sink.write_frame(frame=annotated_frame) + ``` + +
+ + ![heat-map-annotator-example](https://media.roboflow.com/supervision-annotator-examples/heat-map-annotator-example-purple.png){ align=center width="800" } + +
+ +=== "Others" + + === "PercentageBar" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + percentage_bar_annotator = sv.PercentageBarAnnotator() + annotated_frame = percentage_bar_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` + +
+ + ![percentage-bar-annotator-example](https://media.roboflow.com/supervision-annotator-examples/percentage-bar-annotator-example-purple.png){ align=center width="800" } + +
+ + === "Icon" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + icon_paths = ["" for _ in detections] + + icon_annotator = sv.IconAnnotator() + annotated_frame = icon_annotator.annotate( + scene=image.copy(), + detections=detections, + icon_path=icon_paths, + ) + ``` + +
+ + ![icon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/icon-annotator-example.png){ align=center width="800" } + +
+ + === "Background Color" + + ```python + import supervision as sv + + image = ... + detections = sv.Detections(...) + + background_overlay_annotator = sv.BackgroundOverlayAnnotator() + annotated_frame = background_overlay_annotator.annotate( + scene=image.copy(), + detections=detections, + ) + ``` + +
+ + ![background-overlay-annotator-example](https://media.roboflow.com/supervision-annotator-examples/background-color-annotator-example-purple.png){ align=center width="800" } + +
+ + === "Comparison" + + ```python + import supervision as sv + + image = ... + detections_1 = sv.Detections(...) + detections_2 = sv.Detections(...) + + comparison_annotator = sv.ComparisonAnnotator() + annotated_frame = comparison_annotator.annotate( + scene=image.copy(), + detections_1=detections_1, + detections_2=detections_2, + ) + ``` + +
+ + ![comparison-annotator-example](https://media.roboflow.com/supervision-annotator-examples/comparison-annotator-example.png){ align=center width="800" } + +

Try Supervision Annotators on your own image

diff --git a/tests/annotators/test_docs.py b/tests/annotators/test_docs.py new file mode 100644 index 00000000..f9def6ca --- /dev/null +++ b/tests/annotators/test_docs.py @@ -0,0 +1,148 @@ +"""Regression tests for docs/detection/annotators.md tab structure.""" + +import ast +import re +from pathlib import Path + +import pytest + +_REPO_ROOT = Path(__file__).resolve().parent +while not (_REPO_ROOT / "pyproject.toml").exists(): + _REPO_ROOT = _REPO_ROOT.parent + +REPO_ROOT = _REPO_ROOT + +EXPECTED_ANNOTATOR_TAB_GROUPS: dict[str, list[str]] = { + "Outlines": [ + "Box", + "RoundBox", + "BoxCorner", + "Circle", + "Ellipse", + "Polygon", + ], + "Shading": ["Color", "Halo", "Mask"], + "Markers": ["Dot", "Triangle"], + "Labels": ["Label", "RichLabel"], + "Transformative": ["Blur", "Pixelate"], + "Tracking & Aggregation": ["Trace", "HeatMap"], + "Others": [ + "PercentageBar", + "Icon", + "Background Color", + "Comparison", + ], +} + + +def _extract_annotator_tab_groups() -> dict[str, list[str]]: + """Parse annotator tab structure from docs/detection/annotators.md. + + Returns: + Mapping of category name to list of annotator tab labels within that + category. + """ + docs_path = REPO_ROOT / "docs" / "detection" / "annotators.md" + content = docs_path.read_text(encoding="utf-8") + + start_marker = '=== "Outlines"' + end_marker = "Try Supervision Annotators on your own image" + + start = content.find(start_marker) + if start == -1: + pytest.fail( + f"Could not find start marker {start_marker!r} in {docs_path} while " + "parsing annotator example tab groups." + ) + + end = content.find(end_marker, start) + if end == -1: + pytest.fail( + f"Could not find end marker {end_marker!r} in {docs_path} while " + "parsing annotator example tab groups." + ) + if end <= start: + pytest.fail( + f"End marker {end_marker!r} must appear after start marker " + f"{start_marker!r} in {docs_path}." + ) + + example_section = content[start:end] + + groups: dict[str, list[str]] = {} + current_group = None + + for line in example_section.splitlines(): + if match := re.match(r'^(?P\s*)=== "(?P