chore: import upstream snapshot with attribution
Docs/Test Workflow / Test docs build (push) Failing after 0s
Check links & references / links-check (push) Failing after 1s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.10) (push) Failing after 0s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.11) (push) Failing after 0s
PR Conflict Labeler / main (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.12) (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.13) (push) Failing after 0s
Pytest/Test Workflow / Build this Package (push) Failing after 5s
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / testing-guardian (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:06:10 +08:00
commit 9194ef5abd
356 changed files with 103185 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
# see https://docs.codecov.io/docs/codecov-yaml
# Validation check:
# $ curl --data-binary @.codecov.yml https://codecov.io/validate
# https://docs.codecov.io/docs/codecovyml-reference
codecov:
bot: "codecov-io"
strict_yaml_branch: "yaml-config"
require_ci_to_pass: yes
notify:
# after_n_builds: 2
wait_for_ci: yes
coverage:
precision: 0 # 2 = xx.xx%, 0 = xx%
round: nearest # how coverage is rounded: down/up/nearest
range: 40...100 # custom range of coverage colors from red -> yellow -> green
status:
project:
default:
informational: true
target: 95% # specify the target coverage for each commit status
threshold: 10% # allow this little decrease on project
# branches: master
if_ci_failed: error
patch:
default:
informational: true
target: 95% # enforce same coverage target for new/changed code as the project
threshold: 10% # allow only a small decrease on patch coverage
changes: false
# https://docs.codecov.com/docs/github-checks#disabling-github-checks-patch-annotations
github_checks:
annotations: false
comment:
layout: header, diff
require_changes: false
behavior: default # update if exists else create new
# branches: *
+1
View File
@@ -0,0 +1 @@
*.ipynb linguist-vendored
+4
View File
@@ -0,0 +1,4 @@
# These owners will be the default owners for everything in
# the repo. They will be requested for review when someone
# opens a pull request.
* @SkalskiP @soumik12345
+85
View File
@@ -0,0 +1,85 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at community-reports@roboflow.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][mozilla coc].
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][faq]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
[faq]: https://www.contributor-covenant.org/faq
[homepage]: https://www.contributor-covenant.org
[mozilla coc]: https://github.com/mozilla/diversity
[translations]: https://www.contributor-covenant.org/translations
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+506
View File
@@ -0,0 +1,506 @@
# Contributing to Supervision 🛠️
Thank you for your interest in contributing to Supervision!
We are actively improving this library to reduce the amount of work you need to do to solve common computer vision problems.
## Code of Conduct
Please read and adhere to our [Code of Conduct](https://supervision.roboflow.com/latest/code_of_conduct/). This document outlines the expected behavior for all participants in our project.
## Table of Contents
- [Contribution Guidelines](#contribution-guidelines)
- [Contributing Features](#contributing-features)
- [API Design Principles](#api-design-principles)
- [How to Contribute Changes](#how-to-contribute-changes)
- [Installation for Contributors](#installation-for-contributors)
- [Code Style and Quality](#code-style-and-quality)
- [Pre-commit tool](#pre-commit-tool)
- [Docstrings](#docstrings)
- [Type checking](#type-checking)
- [Documentation](#documentation)
- [Cookbooks](#cookbooks)
- [Tests](#tests)
- [License](#license)
## Contribution Guidelines
We welcome contributions to:
1. Add a new feature to the library (guidance below).
2. Improve our documentation and add examples to make it clear how to leverage the supervision library.
3. Report bugs and issues in the project.
4. Submit a request for a new feature.
5. Improve our test coverage.
### Contributing Features ✨
Supervision is designed to provide generic utilities to solve problems. Thus, we focus on contributions that can have an impact on a wide range of projects.
For example, counting objects that cross a line anywhere on an image is a common problem in computer vision, but counting objects that cross a line 75% of the way through is less useful.
Before you contribute a new feature, consider submitting an Issue to discuss the feature so the community can weigh in and assist.
### API Design Principles
Supervision APIs should remain generic, composable, and predictable across model families. Before adding a new integration, annotator option, or data conversion method, check the existing `sv.Detections`, `sv.KeyPoints`, and annotator patterns and follow these principles:
1. **Model integrations normalize raw external outputs into existing Supervision containers.** Use `sv.Detections` for detection, segmentation, and other instance-level predictions that include boxes, masks, class ids, confidence scores, or extra per-instance fields. Use `sv.KeyPoints` for standalone keypoint or pose predictions when keypoints exist independently of detection boxes (e.g. pure pose estimation, landmark detection on pre-cropped images). Use `Detections.keypoints` when keypoints are always co-incident with boxes from the same model — the field stores an `(n, K, 2)` or `(n, K, 3)` array where the optional third channel is per-point confidence in `[0, 1]`.
2. **Do not add a `from_<model>` method when the model already returns a Supervision object.** `from_*` methods are for converting raw outputs from external packages such as Ultralytics, Transformers, Inference, or MediaPipe. If a model's `predict()` method already returns `sv.Detections`, keep that result type and store additional structured payloads in `detections.data` or `detections.metadata` using documented keys.
3. **Annotators render data; filtering and visibility are container state.** Filtering by confidence, class id, tracker id, geometry, or custom data should happen before annotation through the container slicing APIs, for example `detections[detections.confidence > 0.7]` or `key_points[key_points.confidence > 0.5]`. Per-point presentation state, such as a `KeyPoints.visible` mask, may live on the container and be honored consistently by annotators.
4. **Annotator constructor arguments should describe visual presentation, not model-quality gates.** Use constructor arguments for color, thickness, opacity, text, position, style, and generic visualization parameters such as sigma levels. Annotators may skip invalid geometry defensively, including missing points, zero-area boxes, non-finite coordinates, or points marked invisible on the container. They should not introduce confidence thresholds or model-specific quality gates as rendering options.
## How to Contribute Changes
First, fork this repository to your own GitHub account. Click "fork" in the top corner of the `supervision` repository to get started:
![Forking the repository](https://media.roboflow.com/fork.png)
![Creating a repository fork](https://media.roboflow.com/create_fork.png)
Then, run `git clone` to download the project code to your computer.
You should also set up `roboflow/supervision` as an "upstream" remote (that is, tell git that the reference Supervision repository was the source of your fork of it):
```bash
git remote add upstream https://github.com/roboflow/supervision.git
git fetch upstream
```
Move to a new branch using the `git checkout` command:
```bash
git checkout -b <scope>/<your_branch_name> upstream/develop
```
The name you choose for your branch should describe the change you want to make and start with an appropriate prefix:
- `feat/`: for new features (e.g., `feat/line-counter`)
- `fix/`: for bug fixes (e.g., `fix/memory-leak`)
- `docs/`: for documentation changes (e.g., `docs/update-readme`)
- `chore/`: for routine tasks, maintenance, or tooling changes (e.g., `chore/update-dependencies`)
- `test/`: for adding or modifying tests (e.g., `test/add-unit-tests`)
- `refactor/`: for code refactoring (e.g., `refactor/simplify-algorithm`)
Make any changes you want to the project code, then run the following commands to commit your changes:
```bash
git add -A
git commit -m "feat: add line counter functionality"
git push -u origin <your_branch_name>
```
Use conventional commit messages to clearly describe your changes. The format is:
```
<type>[optional scope]: <description>
```
Common types include:
- `feat`: A new feature
- `fix`: A bug fix
- `docs`: Documentation only changes
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, etc)
- `refactor`: A code change that neither fixes a bug nor adds a feature
- `perf`: A code change that improves performance
- `test`: Adding missing tests or correcting existing tests
- `chore`: Changes to the build process or auxiliary tools and libraries
Then, go back to your fork of the `supervision` repository, click "Pull Requests", and click "New Pull Request".
![Opening a pull request](https://media.roboflow.com/open_pr.png)
Make sure the `base` branch is `develop` before submitting your PR.
On the next page, review your changes then click "Create pull request":
![Configuring a pull request](https://media.roboflow.com/create_pr_submit.png)
Next, write a description for your pull request, and click "Create pull request" again to submit it for review:
![Submitting a pull request](https://media.roboflow.com/write_pr.png)
When creating new functions, please ensure you have the following:
1. Docstrings for the function and all parameters.
2. Unit tests for the function.
3. Examples in the documentation for the function.
4. Created an entry in our docs to autogenerate the documentation for the function.
5. Please share a Google Colab with minimal code to test a new feature or reproduce the issue whenever possible. Please ensure that Google Colab can be accessed without any restrictions.
When you submit your Pull Request, you will be asked to sign a Contributor License Agreement (CLA) by the `cla-assistant` GitHub bot. We can only respond to PRs from contributors who have signed the project CLA.
All pull requests will be reviewed by the maintainers of the project. We will provide feedback and ask for changes if necessary.
PRs must pass all tests and linting requirements before they can be merged.
## Installation for Contributors
Before starting your work on the project, set up your development environment:
1. **Clone your fork of the project:**
**Option A: Recommended for most contributors (shallow clone of develop branch):**
```bash
git clone --depth 1 -b develop https://github.com/YOUR_USERNAME/supervision.git
cd supervision
```
Replace `YOUR_USERNAME` with your GitHub username.
> **Note**: Using `--depth 1` creates a shallow clone with minimal history and `-b develop` ensures you start with the development branch. This significantly reduces download size while providing everything needed to contribute.
**Option B: Full repository clone (if you need complete history):**
```bash
git clone https://github.com/YOUR_USERNAME/supervision.git
cd supervision
git checkout develop
```
2. **Set up the upstream remote:**
```bash
git remote add upstream https://github.com/roboflow/supervision.git
git fetch upstream
```
3. **Create and activate a virtual environment:**
**On Linux/macOS:**
```bash
python3 -m venv .venv
source .venv/bin/activate
```
**On Windows:**
```cmd
python -m venv .venv
.venv\Scripts\activate
```
4. **Install `uv`:**
Follow the instructions on the [uv installation page](https://docs.astral.sh/uv/getting-started/installation/).
5. **Install project dependencies:**
```bash
uv pip install -r pyproject.toml --group dev --group docs --extra metrics
```
6. **Verify the setup:**
```bash
uv run pytest
```
## 🎨 Code Style and Quality
### Pre-commit tool
This project uses the [pre-commit](https://pre-commit.com/) tool to maintain code quality and consistency. Before submitting a pull request or making any commits, it is important to run the pre-commit tool to ensure that your changes meet the project's guidelines.
Furthermore, we have integrated a pre-commit GitHub Action into our workflow. This means that with every pull request opened, the pre-commit checks will be automatically enforced, streamlining the code review process and ensuring that all contributions adhere to our quality standards.
To run the pre-commit tool, follow these steps:
1. **Install pre-commit** (already included if you followed the installation steps above):
```bash
uv sync --group dev
```
2. **Navigate to the project's root directory** (if not already there).
3. **Run pre-commit checks**:
```bash
uv run pre-commit run --all-files
```
This will execute the pre-commit hooks configured for this project. If any issues are found, the pre-commit tool will provide feedback on how to resolve them. Make the necessary changes and re-run the command until all issues are resolved.
4. **Install pre-commit as a git hook** (optional but recommended):
```bash
uv run pre-commit install
```
This will automatically run pre-commit checks every time you make a `git commit`.
### Docstrings
All new functions and classes in `supervision` should include docstrings. This is a prerequisite for any new functions and classes to be added to the library.
`supervision` adheres to the [Google Python docstring style](https://google.github.io/styleguide/pyguide.html#383-functions-and-methods). Please refer to the style guide while writing docstrings for your contribution.
Every docstring should include a usage example. When the example only uses `supervision`, NumPy, and the standard library — no optional extras, no external files or network access — strongly prefer `>>>` doctest format so it is automatically verified by the test suite. See [Doctests](#doctests) below for syntax guidance and for when fenced ```` ```python ```` blocks are appropriate instead.
### Type checking
Type hints are required on all new code. mypy is enforced by the pre-commit hook configured in `.pre-commit-config.yaml` — your PR will fail CI if mypy reports errors.
### Readability
Avoid multi-branch conditional expressions inside function or constructor arguments. If an argument needs more than a simple `a if condition else b`, assign it to a named local variable before the call.
### Performance
- Avoid unnecessary copies of NumPy arrays.
- Prefer vectorized operations over Python loops in hot paths.
- Lazy-import heavy framework dependencies (`torch`, `transformers`, `ultralytics`) inside the function that needs them — never at module top level.
### Deprecation policy
**Minimum window**: deprecated APIs must remain for at least **3 minor releases** before removal. Example: deprecated in `0.29.0` → removed in `0.32.0`.
Use the appropriate mechanism depending on what is being deprecated:
- **Module-level alias**: `supervision.utils.internal.warn_deprecated` in the deprecated module's `__init__.py`
- **Renamed parameter**: `supervision.utils.internal.deprecated_parameter` decorator
- **Public function, method, or class**: `@deprecated` from `pydeprecate`
Always specify both the deprecation version and the planned removal version in the message or decorator arguments.
### Deprecated module aliases
`supervision.keypoint` is deprecated since `0.27.0` and will be removed in `0.30.0`. Always import from `supervision.key_points`:
```python
from supervision.key_points import KeyPoints # correct
```
## 📝 Documentation
The `supervision` documentation is stored in a folder called `docs`. The project documentation is built using `mkdocs`.
To run the documentation locally:
1. **Install documentation dependencies** (if not already installed):
```bash
uv sync --group docs
```
2. **Start the documentation server**:
```bash
uv run mkdocs serve
```
3. **Access the documentation** at `http://127.0.0.1:8000` in your browser.
You can learn more about mkdocs on the [mkdocs website](https://www.mkdocs.org/).
## 🧑‍🍳 Cookbooks
We are always looking for new examples and cookbooks to add to the `supervision` documentation. If you have a use case that you think would be helpful to others, please submit a PR with your example. Here are some guidelines for submitting a new example:
- Create a new notebook in the [`docs/notebooks`](https://github.com/roboflow/supervision/tree/develop/docs/notebooks) folder.
- Add a link to the new notebook in [`docs/theme/cookbooks.html`](https://github.com/roboflow/supervision/blob/develop/docs/theme/cookbooks.html). Make sure to add the path to the new notebook, as well as a title, labels, author and supervision version.
- Use the [Count Objects Crossing the Line](https://supervision.roboflow.com/develop/notebooks/count-objects-crossing-the-line/) example as a template for your new example.
- Pin the version of `supervision` you are using in the notebook.
- Place an appropriate "Open in Colab" button at the top of the notebook. You can find an example of such a button in the aforementioned `Count Objects Crossing the Line` cookbook.
- **Notebook should be self-contained**. If you rely on external data (videos, images, etc.) or libraries, include download and installation commands in the notebook.
- Annotate the code with appropriate comments, including links to the documentation describing each of the tools you have used.
## 🧪 Tests
[`pytest`](https://docs.pytest.org/en/7.1.x/) is used to run our tests.
To run tests:
```bash
uv run pytest
```
To run tests with coverage:
```bash
uv run pytest --cov=supervision
```
### Test Structure
Follow **Arrange-Act-Assert (AAA)**: one setup block, one action, one assertion group per test. Never put two independent actions in the same test.
**Class grouping:** Group related tests into a class. The class name carries the unit under test; method names describe the expected outcome only — not the mechanism.
```python
class TestDetectionsWithNms:
def test_keeps_highest_confidence_detection(self): ...
def test_suppresses_lower_score_when_overlap_exceeds_threshold(self): ...
def test_raises_when_confidence_missing(self): ...
```
**Parametrize aggressively:** Three or more structurally identical tests should become a single `@pytest.mark.parametrize` case. Use `pytest.param(..., id="slug")` per case — not `ids=[...]` on the decorator — so the ID stays co-located with its arguments and survives reordering.
```python
@pytest.mark.parametrize(
("overlap_metric", "expected_keep"),
[
pytest.param(OverlapMetric.IOU, [True, True], id="iou-keeps-both"),
pytest.param(OverlapMetric.IOS, [True, False], id="ios-suppresses-small"),
],
)
def test_overlap_metric_determines_suppression(
overlap_metric: OverlapMetric, expected_keep: list[bool]
) -> None:
"""Small box inside large: IOU keeps both; IOS suppresses small."""
...
```
**Docstrings:** Every test function/method requires at minimum a one-line docstring (within the project line length configured in `pyproject.toml`). Describe the scenario, not the implementation.
### Doctests
**Guidance:** when an example uses only `supervision`, NumPy, and the standard library — no optional extras (e.g. no `--extra metrics` packages), no external files, no network, no devices — prefer `>>>` doctest format so it is automatically verified by the test suite. Fenced ```` ```python ```` blocks are appropriate when the example cannot reasonably be executed (e.g. loading a third-party model, reading a video file) or when the primary purpose is demonstrating error/exception behaviour rather than return values.
Doctests run automatically as part of the test suite via `--doctest-modules` in `pyproject.toml`. The `ELLIPSIS` and `NORMALIZE_WHITESPACE` flags are enabled globally, so `...` matches any output fragment and minor whitespace differences are ignored.
```bash
uv run pytest --doctest-modules src/
```
**Writing a doctest**
Use the `Example:` section of a Google-style docstring. Prefix each input line with `>>>` and each continuation line with `...`. Place expected output immediately after the last input line with no blank line between them.
```python
def clip_boxes(xyxy: np.ndarray, resolution_wh: tuple) -> np.ndarray:
"""Clip bounding boxes to frame boundaries.
Args:
xyxy: Box coordinates as (N, 4) float array.
resolution_wh: Frame size as (width, height).
Returns:
Clipped boxes as (N, 4) float array.
Example:
>>> import numpy as np
>>> import supervision as sv
>>> boxes = np.array([[-10, -5, 120, 80]], dtype=np.float32)
>>> sv.clip_boxes(boxes, resolution_wh=(100, 60))
array([[ 0., 0., 100., 60.]], dtype=float32)
"""
```
### Key rules
- **Single-line expression** — write the repr as expected output: `>>> len(result)` → `1`
- **Multi-line statement** — use `...` continuation: `>>> arr = np.array([` / `... [1, 2],` / `... ])`
- **Print output** — write the printed string as expected output (no quotes).
- **`None` return** — no output line needed (suppress with assignment or `_ =`).
- **Large/variable arrays** — use `ELLIPSIS`: `array([...])` matches any content.
- **`# doctest: +SKIP`** — use only as a last resort for genuinely non-runnable lines (e.g. a GPU-only call inside an otherwise runnable example). Prefer splitting the example into two blocks instead.
Fenced ```` ```python ```` blocks remain appropriate for:
- Examples that import optional extras (`supervision[metrics]`, `torch`, `ultralytics`).
- Examples that read files, capture video, or require a running service.
- Illustrative pseudocode that is intentionally incomplete.
## 🔍 PR Review Guidelines
These guidelines help reviewers provide consistent, actionable feedback efficiently. Your goals: validate completeness, identify risks, provide actionable feedback, and highlight quality gaps.
### Overall Recommendation
Start with a clear recommendation using these levels:
- 🟢 **Approve** — Ready to merge
- 🟡 **Minor Suggestions** — Improvements recommended but not blocking
- 🟠 **Request Changes** — Must address issues before merge
- 🔴 **Block** — Critical issues require major rework
Example: `🟠 Request Changes — Missing unit tests for PolygonMerger and no mkdocs entry.`
### PR Completeness
Verify requirements are met (✅ Complete / ⚠️ Incomplete / ❌ Missing / 🔵 N/A):
- [ ] Clear description of what changed and why
- [ ] Tests added/updated for new functionality or bug fixes
- [ ] Docstrings follow [Google-style](https://google.github.io/styleguide/pyguide.html#383-functions-and-methods)
- [ ] Docs entry added to mkdocs (new functions/classes only)
- [ ] Google Colab provided (if demonstrating feature/fix)
- [ ] Screenshots/videos included (visual changes only)
Call out missing items explicitly in your review.
### Quality Scores
Use **n/5 scoring** with inline code comments for specifics:
**Code Quality (n/5):**
- 5/5 🟢 Excellent — 4/5 🟢 Good — 3/5 🟡 Acceptable — 2/5 🟠 Needs Work — 1/5 🔴 Poor
- Check: correctness (edge cases, None checks, bounds), Python best practices (idiomatic patterns, error handling, type hints), project conventions (docstrings, linting, import order, PEP 8 naming)
**Testing (n/5):**
- 5/5 🟢 Comprehensive — 4/5 🟢 Good — 3/5 🟡 Adequate — 2/5 🟠 Insufficient — 1/5 🔴 Missing
- Verify: unit tests for new code, edge cases covered, specific assertions, realistic scenarios, clear test names
**Documentation (n/5):**
- 5/5 🟢 Excellent — 4/5 🟢 Good — 3/5 🟡 Adequate — 2/5 🟠 Insufficient — 1/5 🔴 Missing
- Confirm: docstrings for public functions/classes, parameters/returns/exceptions documented, usage examples, mkdocs integration, changelog entry for user-facing changes
### Risk Assessment
Flag risks with severity (5/5 🔴 Critical — 4/5 🟠 High — 3/5 🟡 Medium — 2/5 🟢 Low — 1/5 🟢 Negligible):
**Common risk categories:**
1. **Breaking changes** — API changes, removed features, behavior modifications (must include migration guide)
2. **Performance** — Inefficient algorithms, memory-intensive operations, bottlenecks
3. **Compatibility** — New Python/dependency requirements, platform-specific code
4. **Security** — Unvalidated input, code execution risks, data exposure
### Review Summary Template
```markdown
## Review Summary
**Recommendation:** [emoji] [Status] — [justification]
**PR Completeness:**
- ✅ Complete: [items]
- ❌ Missing: [gaps]
**Quality Scores:**
- Code: n/5 [emoji] — [reason]
- Testing: n/5 [emoji] — [reason]
- Documentation: n/5 [emoji] — [reason]
**Risk Level:** n/5 [emoji] — [description]
**Critical Issues (Must Fix):**
1. [Issue] — See comment on `file.py`
**Suggestions (Optional):**
1. [Improvement] — See suggestion on `file.py`
**Next Steps:**
1. [Action item]
```
### Review Best Practices
**DO:** Use inline GitHub comments with suggestions, explain *why* (not just *what*), distinguish blocking vs. nice-to-have, acknowledge good work, run linter if needed (`uv run pre-commit run --all-files`)
**DON'T:** Mention line numbers in summary (use inline comments), give vague feedback, nitpick style (defer to tools), assume knowledge of conventions, block on minor issues
**Tone:** Be respectful, specific, pragmatic, and consistent. Focus on actionable feedback that moves PRs toward merge.
## 📄 License
By contributing, you agree that your contributions will be licensed under an [MIT license](../LICENSE.md).
+68
View File
@@ -0,0 +1,68 @@
name: 🐞 Bug Report
title: "[Bug]: "
description: Report a bug or unexpected behavior in Supervision
labels: [bug]
body:
- type: checkboxes
attributes:
label: Search before asking
description: Please search [issues](https://github.com/roboflow/supervision/issues) and [discussions](https://github.com/roboflow/supervision/discussions) first.
options:
- label: I have searched the issues and discussions and found no similar bug report.
required: true
- type: textarea
attributes:
label: Bug
description: Describe the bug, what you expected, and what actually happened.
placeholder: |
**What's the bug?**
Brief description...
**Expected behavior:**
What should happen...
**Actual behavior:**
What actually happens...
**Error/Traceback (if any):**
```python
# Paste error messages here
```
validations:
required: true
- type: textarea
attributes:
label: Environment
description: Your setup details
placeholder: |
- Supervision: 0.23.0
- Python: 3.10.12
- OS: Ubuntu 22.04
value: |
- Supervision:
- Python:
- OS:
validations:
required: true
- type: textarea
attributes:
label: Minimal Reproducible Example
description: Code to reproduce the bug ([guide](https://stackoverflow.com/help/minimal-reproducible-example))
placeholder: |
```python
import supervision as sv
# Your code here
```
validations:
required: false
- type: checkboxes
attributes:
label: Are you willing to submit a PR?
description: (Optional) We encourage community contributions!
options:
- label: Yes I'd like to help by submitting a PR!
+17
View File
@@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: ❓ Ask a Question
url: https://github.com/roboflow/supervision/discussions/new?category=q-a
about: Ask questions about using Supervision in GitHub Discussions
- name: 📚 Documentation
url: https://supervision.roboflow.com/
about: Check the official Supervision documentation for guides and API references
- name: 💬 GitHub Discussions
url: https://github.com/roboflow/supervision/discussions
about: Join community discussions, share ideas, and get help
- name: 🌟 Show and Tell
url: https://github.com/roboflow/supervision/discussions/categories/show-and-tell
about: Share your projects and creations built with Supervision
- name: 🗣️ Roboflow Discord
url: https://discord.com/invite/GbfgXGJ8Bk
about: Join our Discord to collaborate with other community members
@@ -0,0 +1,50 @@
name: 🤩 Feature Request
title: "[Feature]: "
description: Suggest a new feature or improvement
labels: [enhancement]
body:
- type: markdown
attributes:
value: |
Thank you for submitting a Supervision 🤩 Feature Request!
- type: checkboxes
attributes:
label: Search before asking
description: Please search [issues](https://github.com/roboflow/supervision/issues) and [discussions](https://github.com/roboflow/supervision/discussions) first.
options:
- label: I have searched the issues and discussions and found no similar feature request.
required: true
- type: textarea
attributes:
label: Feature Description
description: What feature would you like and why?
placeholder: |
**What:** Describe the feature...
**Why:** What problem does it solve? Who would benefit?
**How (optional):** Any ideas on implementation?
validations:
required: true
- type: textarea
attributes:
label: Example Usage
description: (Optional) Show how you'd like to use this feature
placeholder: |
```python
import supervision as sv
# Your example usage here
```
validations:
required: false
- type: checkboxes
attributes:
label: Are you willing to submit a PR?
description: (Optional) We encourage community contributions!
options:
- label: Yes I'd like to help by submitting a PR!
+67
View File
@@ -0,0 +1,67 @@
<details>
<summary>Before submitting</summary>
- [ ] Self-reviewed the code
- [ ] Updated documentation, follow [Google-style](https://google.github.io/styleguide/pyguide.html#383-functions-and-methods)
- [ ] Added docs entry for autogeneration (if new functions/classes)
- [ ] Added/updated tests
- [ ] All tests pass locally
</details>
## Description
<!-- Provide a clear and concise description of your changes -->
## Type of Change
<!-- Mark the relevant option with an "x" and delete the others -->
- 🐛 Bug fix (non-breaking change which fixes an issue)
- ✨ New feature (non-breaking change which adds functionality)
- 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
- 📝 Documentation update
- 🧪 Test update
- 🔨 Refactoring (no functional changes)
- ⚡ Performance improvement
- 🔧 Chore (dependencies, configs, etc.)
## Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here -->
Closes #(issue)
## Changes Made
<!-- List the main changes made in this PR -->
-
-
-
## Testing
<!-- Describe the tests you ran and how to reproduce them -->
- [ ] I have tested this code locally
- [ ] I have added unit tests that prove my fix is effective or that my feature works
- [ ] All new and existing tests pass
## Google Colab (optional)
<!-- If applicable, provide a link to a Google Colab notebook demonstrating the feature/fix -->
<!-- Ensure the notebook is publicly accessible -->
Colab link:
## Screenshots/Videos (optional)
<!-- If applicable, add screenshots or videos to demonstrate the changes -->
## Additional Notes
<!-- Any additional information that reviewers should know -->
+146
View File
@@ -0,0 +1,146 @@
# GitHub Copilot Instructions for Supervision
This file provides context-aware guidance for GitHub Copilot when working in the Supervision repository.
---
## 📚 Repository Overview
**Supervision** is a Python library providing reusable computer vision utilities for working with object detection models (YOLO, SAM, etc.). It offers tools for detections processing, tracking, annotation, and dataset management.
- **Languages**: Python 3.10+
- **Key Dependencies**: NumPy, OpenCV, SciPy
- **License**: MIT
---
## 🏗️ Project Structure
```
supervision/
├── src/
│ └── supervision/ # Main library code
│ ├── detection/ # Detection utilities
│ ├── draw/ # Annotation and visualization
│ ├── tracker/ # Object tracking
│ ├── dataset/ # Dataset management
│ └── utils/ # Shared utilities
├── tests/ # Test suite (mirrors src/supervision/)
├── docs/ # MkDocs documentation
└── examples/ # Usage examples
```
---
## 🔧 Development Commands
**Setup:**
```bash
# Install dependencies
uv sync --group dev --group docs --extra metrics
# Install pre-commit hooks
uv run pre-commit install
```
**Quality Checks:**
```bash
# Run all pre-commit hooks (formatting, linting, type checking)
uv run pre-commit run --all-files
# Run tests with coverage
uv run pytest --cov=supervision
```
**Documentation:**
```bash
# Serve docs locally at http://127.0.0.1:8000
uv run mkdocs serve
```
---
## 💻 Code Conventions
### General Guidelines
- Follow **[AGENTS.md](../AGENTS.md)** for task-based development workflows
- Reference **[CONTRIBUTING.md](CONTRIBUTING.md)** for detailed contribution guidelines
- All code must pass `pre-commit` hooks before committing
### Code Style
- **Formatting**: Enforced by `ruff-format`, `prettier` (pre-commit)
- **Linting**: Enforced by `ruff-check` (pre-commit)
- **Type Hints**: Required on all new code
- **Docstrings**: Required using [Google Python style](https://google.github.io/styleguide/pyguide.html#383-functions-and-methods)
- Must include usage examples with primitive values
- Serve as runnable documentation
### Performance
- Avoid unnecessary NumPy array copies
- Prefer vectorized operations over Python loops
- Use OpenCV operations efficiently
### API Design
- Follow existing naming patterns for consistency
- Maintain backward compatibility unless explicitly breaking
- Prefer functional utilities over complex classes
---
## 🧪 Testing Requirements
All new features must include:
- Unit tests covering happy path and edge cases
- Tests for `None`, empty inputs, large arrays, boundary conditions
- Clear test names describing what they validate
- Proper assertions (not just "no exception raised")
---
## 📝 Documentation Requirements
For new public functions/classes:
- Google-style docstrings with parameters, returns, exceptions
- Usage examples in docstrings
- Entry in appropriate `docs/*.md` file
- Reference in `mkdocs.yml` navigation
---
## 🔍 Pull Request Reviews
**When reviewing PRs, follow the comprehensive [PR Review Guidelines](CONTRIBUTING.md#pr-review-guidelines).**
Quick checklist:
- Tests included and passing
- Docstrings follow Google style with examples
- Pre-commit hooks pass
- Breaking changes documented
- Score code quality, testing, docs (n/5 scale)
- Use inline comments + GitHub suggestion format
---
## 🌿 Branching & Commits
- Branch from `develop` using prefixes: `feat/`, `fix/`, `docs/`, `refactor/`, `perf/`, `test/`, `chore/`
- Use **conventional commits**: `feat:`, `fix:`, `docs:`, `refactor:`, `perf:`, `test:`, `chore:`
- All PRs target `develop` branch
---
## 🎯 Context-Aware Behavior
- **For general development tasks**: Follow [AGENTS.md](../AGENTS.md)
- **For pull request reviews**: Follow [PR Review Guidelines](CONTRIBUTING.md#pr-review-guidelines)
- **For detailed processes**: Consult [CONTRIBUTING.md](CONTRIBUTING.md)
+26
View File
@@ -0,0 +1,26 @@
version: 2
updates:
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
commit-message:
prefix: ⬆️
target-branch: "develop"
groups:
github-actions:
patterns:
- "*"
# Python
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
commit-message:
prefix: ⬆️
target-branch: "develop"
+35
View File
@@ -0,0 +1,35 @@
verbose = "info"
no_progress = true
include_verbatim = true
retry_wait_time = 10
max_retries = 3
max_concurrency = 8
cache = false
accept = [
200, # OK
408, # Request Timeout
# 429 means the server received the request and is actively rate-limiting — the URL is
# reachable. Real dead links return 404, 410, or fail to connect/resolve; none of
# those produce a 429, so accepting it here does not hide broken links.
429, # Too Many Requests (rate-limited but reachable; does not mask dead links)
# CI regularly sees momentary 502/503/504 from large, healthy hosts (github.com,
# supervision.roboflow.com), and in-run retries tend to land inside the same
# incident window. Genuinely dead links surface as 404, 410, or connection/DNS
# failures, which remain rejected.
502, # Bad Gateway (transient upstream hiccup)
503, # Service Unavailable (transient overload or maintenance)
504, # Gateway Timeout (transient upstream hiccup)
]
exclude = [
"https://github.com/YOUR_USERNAME/supervision.git", # hint for forking contributors
"http://127.0.0.1:8000", # hint for local docs server
"https://sam2.metademolab.com/", # returns 403 Forbidden
"https://snyk.io/advisor/python/supervision/badge.svg", # badge URL
"https://trendshift.io", # badge API times out in CI
"https://universe.roboflow.com/",
"https://universe.roboflow.com/model-examples/segmented-animals-basic",
# fixme: this page returns 401 Unauthorized when accessed and 404 Not Found when accessed with browser,
# which is weird and should be investigated
"https://huggingface.co/spaces/Roboflow/Annotators",
]
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""
Script to augment relative links in markdown files to GitHub URLs.
"""
import argparse
import os
import re
from re import Match
def get_repo_root() -> str:
"""Get the repository root path."""
script_dir = os.path.dirname(os.path.abspath(__file__))
return os.path.dirname(os.path.dirname(script_dir))
def augment_links_in_file(file_path: str, branch: str = "main") -> None:
"""
Augment relative links in a markdown file to GitHub URLs.
Args:
file_path: Path to the markdown file.
branch: Branch name, default "main".
"""
repo_root = get_repo_root()
if not file_path.endswith(".md"):
return
with open(file_path) as f:
content = f.read()
def replace_link(match: Match[str]) -> str:
full_match = match.group(0)
text = match.group(2)
url = match.group(3)
if not url.startswith("http"):
# Resolve relative to an absolute path
abs_path = os.path.normpath(os.path.join(os.path.dirname(file_path), url))
if os.path.exists(abs_path):
# Use 'tree' for directories and 'blob' for files
ref = "tree" if os.path.isdir(abs_path) else "blob"
rel_to_root = os.path.relpath(abs_path, repo_root)
new_url = f"https://github.com/roboflow/supervision/{ref}/{branch}/{rel_to_root}"
if full_match.startswith("!"):
return f"![{text}]({new_url})"
else:
return f"[{text}]({new_url})"
return full_match
new_content = re.sub(r"(!?)\[([^\]]+)\]\(([^)]+)\)", replace_link, content)
with open(file_path, "w") as f:
f.write(new_content)
def main() -> None:
parser = argparse.ArgumentParser(
description="Augment relative links to GitHub URLs."
)
parser.add_argument("--branch", default="main", help="Branch name")
parser.add_argument("files", nargs="+", help="Files to process")
args = parser.parse_args()
for file in args.files:
augment_links_in_file(file, args.branch)
if __name__ == "__main__":
main()
+56
View File
@@ -0,0 +1,56 @@
name: Build Package
permissions:
contents: read
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: "3.10"
link-check:
required: false
type: boolean
default: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout the repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: 🐍 Install uv and set Python version ${{ inputs.python-version }}
uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0
with:
python-version: ${{ inputs.python-version }}
activate-environment: true
- name: 🎨 Augment paths in README
run: |
python .github/scripts/augment_links.py README.md --branch ${{ github.head_ref || github.ref_name }}
cat README.md
- name: 🔗 Link Checker
if: inputs.link-check
uses: lycheeverse/lychee-action@v2
with:
lycheeVersion: v0.22.0
args: |
--config .github/lychee.toml
README.md
fail: true
- name: 🏗️ Build source and wheel distributions
run: |
uv sync --frozen --group build
uv build
twine check --strict dist/*
- name: 📤 Upload distribution artifacts
uses: actions/upload-artifact@v7
with:
name: dist
path: dist/
+37
View File
@@ -0,0 +1,37 @@
name: Docs/Test Workflow
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: docs-test-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
# Restrict permissions by default
permissions:
contents: read # Required for checkout
checks: write # Required for test reporting
jobs:
docs-build:
name: Test docs build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: 📥 Checkout the repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: 🐍 Install uv and set Python
uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0
with:
python-version: "3.10"
activate-environment: true
- name: 🏗️ Install dependencies
run: uv sync --frozen --group docs
- name: 🧪 Test Docs Build
run: mkdocs build --verbose
+37
View File
@@ -0,0 +1,37 @@
name: Check links & references
permissions:
contents: read
on:
push:
branches: [main, develop]
pull_request:
schedule:
# Run once a week on Sundays
- cron: "0 9 * * 0"
concurrency:
group: ci-check-links-${{ github.ref }}
cancel-in-progress: true
jobs:
links-check:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: 🔗 Link Checker
uses: lycheeverse/lychee-action@v2
with:
lycheeVersion: v0.22.0
args: |
--config .github/lychee.toml
'./**/*.md'
# TODO: enable also following file types
# './**/*.toml'
# './**/*.yml'
# './**/*.yaml'
# './**/*.py'
fail: true
token: ${{ secrets.GITHUB_TOKEN }}
+90
View File
@@ -0,0 +1,90 @@
name: Pytest/Test Workflow
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
permissions:
contents: read
concurrency:
group: pytest-test-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
build-pkg:
name: Build this Package
uses: ./.github/workflows/build-package.yml
with:
# only run link check on PRs from the same repo
link-check: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
run-tests:
name: Import Test and Pytest Run
# needs: build # todo: consider using this build package for testing
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
runs-on: ${{ matrix.os }}
steps:
- name: 📥 Checkout the repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
- name: 🚀 Install Packages
run: uv sync --frozen --group dev --extra metrics
- name: 📦 Run the Import test
run: python -c "import supervision; from supervision import assets; from supervision import metrics; print(supervision.__version__)"
- name: 🧪 Run the Test
run: pytest src/ tests/ --cov=supervision --cov-report=xml
- name: Generate Coverage Report
run: |
coverage xml
coverage report
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: "coverage.xml"
flags: cpu,${{ runner.os }},python${{ matrix.python-version }}
env_vars: OS,PYTHON
name: codecov-umbrella
fail_ci_if_error: false
- name: Minimize uv cache
run: uv cache prune --ci
testing-guardian:
runs-on: ubuntu-latest
needs: run-tests
if: always()
steps:
- name: 📋 Display test result
run: echo "${{ needs.run-tests.result }}"
- name: ❌ Fail guardian on test failure
if: needs.run-tests.result == 'failure'
run: exit 1
# Ensure that cancelled or skipped test runs still cause this guardian job to fail,
# using an explicit exit code instead of relying on timeout behavior.
- name: ⚠️ cancelled or skipped...
if: contains(fromJSON('["cancelled", "skipped"]'), needs.run-tests.result)
run: |
echo "run-tests job result is '${{ needs.run-tests.result }}'; failing explicitly."
exit 1
- name: ✅ tests succeeded
if: needs.run-tests.result == 'success'
run: echo "All tests completed successfully in job 'run-tests'."
+42
View File
@@ -0,0 +1,42 @@
name: Clear cache
on:
schedule:
- cron: "0 0 1 * *" # Run at midnight on the first day of every month
workflow_dispatch:
# Restrict permissions by default
permissions:
actions: write # Required for cache management
jobs:
clear-cache:
name: Clear cache
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Clear cache
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
console.log("Starting cache cleanup...")
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
let deletedCount = 0
for (const cache of caches.data.actions_caches) {
console.log(`Deleting cache: ${cache.key} (${cache.size_in_bytes} bytes)`)
try {
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
deletedCount++
} catch (error) {
console.error(`Failed to delete cache ${cache.key}: ${error.message}`)
}
}
console.log(`Cache cleanup completed. Deleted ${deletedCount} caches.`)
+26
View File
@@ -0,0 +1,26 @@
name: PR Conflict Labeler
on:
# So that PRs touching the same files as the push are updated
push:
branches:
- main
- develop
# So that the `dirtyLabel` is removed if conflicts are resolved
# We recommend `pull_request_target` so that github secrets are available.
# In `pull_request` we wouldn't be able to change labels of fork PRs
pull_request_target:
types: [synchronize]
permissions:
pull-requests: write
issues: write
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: check if prs are dirty
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: "has conflicts"
repoToken: "${{ secrets.GITHUB_TOKEN }}"
+171
View File
@@ -0,0 +1,171 @@
name: Docs/Build and Publish
# Deploy matrix:
# push develop -> mike deploy develop
# push release/latest -> mike deploy latest
# release published -> mike deploy <tag> only; does not move /latest/
on:
push:
branches:
- develop
- release/latest
workflow_dispatch:
release:
types: [published]
# Ensure only one concurrent deployment
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref}}
cancel-in-progress: true
# Restrict permissions by default
permissions:
contents: write # Required for committing to gh-pages
pages: write # Required for deploying to Pages
pull-requests: write # Required for PR comments
jobs:
docs-build-deploy:
name: Publish Docs
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: 📥 Checkout the repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: 🐍 Install uv and set Python
uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0
with:
python-version: "3.10"
activate-environment: true
- name: 🏗️ Install dependencies
run: uv sync --frozen --group docs
- name: ⚙️ Configure git for github-actions
run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
- name: 🚀 Deploy Development Docs
if: (github.event_name == 'push' && github.ref == 'refs/heads/develop') || github.event_name == 'workflow_dispatch'
env:
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.GITHUB_TOKEN }}
run: |
mike deploy --push develop
- name: 🚀 Deploy Latest Docs
if: github.event_name == 'push' && github.ref == 'refs/heads/release/latest'
env:
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.GITHUB_TOKEN }}
run: |
if mike list | grep -Eq '^latest(\s|$)'; then mike delete latest; fi
mike deploy --push latest
- name: 🏷️ Determine release deployment metadata
id: release_metadata
run: |
is_rc=false
release_tag=""
if [[ "$GITHUB_EVENT_NAME" == "release" ]]; then
release_tag="${GITHUB_REF_NAME#v}"
release_tag="${release_tag%.post*}"
release_tag_lower="${release_tag,,}"
# Match RC suffixes with separators (1.0-rc1, 1.0.rc1) or compact form (1.0rc1).
if [[ "$release_tag_lower" =~ (^|[._-])rc[0-9]+$ ]] || [[ "$release_tag_lower" =~ [0-9]rc[0-9]+$ ]]; then
is_rc=true
fi
fi
echo "is_rc=$is_rc" >> "$GITHUB_OUTPUT"
echo "release_tag=$release_tag" >> "$GITHUB_OUTPUT"
- name: 🚀 Deploy Release Docs
if: github.event_name == 'release' && github.event.action == 'published' && steps.release_metadata.outputs.is_rc != 'true'
env:
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.GITHUB_TOKEN }}
run: |
mike deploy --push "${{ steps.release_metadata.outputs.release_tag }}"
# IndexNow key: 0d5d9799b1cc4a39825146388c6781eb
# This key must stay in sync across three files:
# docs/0d5d9799b1cc4a39825146388c6781eb.txt (key file served at site root)
# docs/theme/main.html (indexnow-key meta tag)
# this workflow (inject step + notify step below)
# Bing/Yandex fetch https://supervision.roboflow.com/<key>.txt to verify ownership.
# Do NOT rename or delete the .txt file or change the key string without updating all three.
- name: 🌐 Inject GEO root files into gh-pages
if: >
(github.event_name == 'push' && github.ref == 'refs/heads/develop') ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && github.ref == 'refs/heads/release/latest') ||
(github.event_name == 'release' && github.event.action == 'published' && steps.release_metadata.outputs.is_rc != 'true')
run: |
cp docs/robots.txt /tmp/robots.txt
cp docs/llms.txt /tmp/llms.txt
cp docs/llms.full.txt /tmp/llms.full.txt
cp docs/llms-100k.txt /tmp/llms-100k.txt
cp docs/_headers /tmp/headers.txt
cp docs/0d5d9799b1cc4a39825146388c6781eb.txt /tmp/indexnow.txt
if [[ "$GITHUB_REF" == "refs/heads/release/latest" ]]; then
version_dir="latest"
else
version_dir=""
fi
git fetch origin gh-pages
git checkout gh-pages
cp /tmp/robots.txt robots.txt
cp /tmp/llms.txt llms.txt
cp /tmp/llms.full.txt llms.full.txt
cp /tmp/llms-100k.txt llms-100k.txt
cp /tmp/headers.txt _headers
cp /tmp/indexnow.txt 0d5d9799b1cc4a39825146388c6781eb.txt
if [[ -n "$version_dir" && -f "$version_dir/sitemap.xml" ]]; then
cp "$version_dir/sitemap.xml" sitemap.xml
gzip -9 -c sitemap.xml > sitemap.xml.gz
fi
files_to_add=(
robots.txt
llms.txt
llms.full.txt
llms-100k.txt
_headers
0d5d9799b1cc4a39825146388c6781eb.txt
)
if [[ -f "sitemap.xml" ]]; then
files_to_add+=(sitemap.xml)
fi
if [[ -f "sitemap.xml.gz" ]]; then
files_to_add+=(sitemap.xml.gz)
fi
git add "${files_to_add[@]}"
git diff --cached --quiet || git commit -m "chore: update GEO root files"
git push origin gh-pages
- name: 📡 Notify IndexNow
if: >
(github.event_name == 'push' && github.ref == 'refs/heads/develop') ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && github.ref == 'refs/heads/release/latest')
run: |
curl -s -o /dev/null -w "%{http_code}" -X POST "https://api.indexnow.org/IndexNow" \
-H "Content-Type: application/json; charset=utf-8" \
-d '{
"host": "supervision.roboflow.com",
"key": "0d5d9799b1cc4a39825146388c6781eb",
"keyLocation": "https://supervision.roboflow.com/0d5d9799b1cc4a39825146388c6781eb.txt",
"urlList": [
"https://supervision.roboflow.com/",
"https://supervision.roboflow.com/latest/",
"https://supervision.roboflow.com/latest/how_to/detect_and_annotate/",
"https://supervision.roboflow.com/latest/how_to/track_objects/",
"https://supervision.roboflow.com/latest/how_to/detect_small_objects/",
"https://supervision.roboflow.com/latest/how_to/filter_detections/",
"https://supervision.roboflow.com/latest/how_to/save_detections/",
"https://supervision.roboflow.com/latest/how_to/count_in_zone/",
"https://supervision.roboflow.com/latest/how_to/benchmark_a_model/",
"https://supervision.roboflow.com/latest/how_to/process_datasets/"
]
}' || true
+51
View File
@@ -0,0 +1,51 @@
name: Publish Supervision Pre-Releases to PyPI
on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+a[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+b[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+.a[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+.b[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+.rc[0-9]+"
workflow_dispatch:
pull_request:
branches: [main, develop]
paths:
- ".github/workflows/build-package.yml"
- ".github/workflows/publish-pre-release.yml"
permissions: {} # Explicitly remove all permissions by default
jobs:
build:
permissions:
contents: read
uses: ./.github/workflows/build-package.yml
publish-pre-release:
name: Publish Pre-release Package
needs: build
runs-on: ubuntu-latest
environment:
name: test
url: https://pypi.org/project/supervision/
timeout-minutes: 10
permissions:
id-token: write # Required for PyPI publishing
contents: read # Required for checkout
steps:
- name: 📥 Download distribution artifacts
uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- name: List distribution artifacts
run: ls -lh dist/
- name: 🚀 Publish to PyPi
if: github.event_name != 'pull_request'
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
attestations: true
+53
View File
@@ -0,0 +1,53 @@
name: Publish Supervision Releases to PyPI
on:
release:
types: [published]
workflow_dispatch:
pull_request:
branches: [main, develop]
paths:
- ".github/workflows/build-package.yml"
- ".github/workflows/publish-release.yml"
permissions: {} # Explicitly remove all permissions by default
jobs:
build:
permissions:
contents: read
uses: ./.github/workflows/build-package.yml
publish-release:
name: Publish Release Package
needs: build
runs-on: ubuntu-latest
environment:
name: release
url: https://pypi.org/project/supervision/
timeout-minutes: 10
permissions:
id-token: write # Required for PyPI publishing
contents: write # Required for checkout and upload assets
steps:
- name: 📥 Download distribution artifacts
uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- name: List distribution artifacts
run: ls -lh dist/
- name: 📦 Upload assets to Release
if: github.event_name == 'release'
uses: AButler/upload-release-assets@v4.0
with:
files: "dist/*"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: 🚀 Publish to PyPi
# We only want to publish to PyPi if the event is a release and it's not a pre-release.
if: (github.event_name == 'release' && github.event.release.prerelease != true) || github.event_name == 'workflow_dispatch'
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
attestations: true
+44
View File
@@ -0,0 +1,44 @@
name: Publish Supervision Releases to TestPyPI
on:
workflow_dispatch:
pull_request:
branches: [main, develop]
paths:
- ".github/workflows/build-package.yml"
- ".github/workflows/publish-testpypi.yml"
permissions: {} # Explicitly remove all permissions by default
jobs:
build:
permissions:
contents: read
uses: ./.github/workflows/build-package.yml
publish-testpypi:
name: Publish Release Package
needs: build
runs-on: ubuntu-latest
environment:
name: release
url: https://pypi.org/project/supervision/
timeout-minutes: 10
permissions:
id-token: write # Required for PyPI publishing
contents: read # Required for checkout
steps:
- name: 📥 Download distribution artifacts
uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- name: List distribution artifacts
run: ls -lh dist/
- name: 🚀 Publish to Test-PyPi
if: github.event_name != 'pull_request'
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
repository-url: https://test.pypi.org/legacy/
attestations: true
+178
View File
@@ -0,0 +1,178 @@
# IDE
.idea/
.vscode/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
.ruff_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# OSX folder attributes
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
# Windows
Thumbs.db
Desktop.ini
# Linux
*~
.directory
.Trash-*
# local data
data/
# Claude working scratchpad (plans, lessons, ephemeral artefacts)
.claude/logs/
.claude/state/
.claude/worktrees/
.developments/
.plans/
.notes/
.reports/
.temp/
.tmp/
_outputs/
_resolutions/
_reviews/
tasks/
*.local.md
output/
notebooks/
releases/
+85
View File
@@ -0,0 +1,85 @@
default_language_version:
python: python3
ci:
autofix_prs: true
autoupdate_schedule: weekly
autofix_commit_msg: "fix(pre_commit): 🎨 auto format pre-commit hooks"
autoupdate_commit_msg: "chore(pre_commit): ⬆ pre_commit autoupdate"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: check-yaml
args: ["--unsafe"]
- id: check-executables-have-shebangs
- id: check-json
- id: check-toml
- id: check-case-conflict
- id: check-added-large-files
args: ["--maxkb=500", "--enforce-all"]
exclude: uv.lock|.*\.ipynb$
- id: detect-private-key
- id: pretty-format-json
exclude: demo.ipynb
args: ["--autofix", "--no-sort-keys", "--indent=4"]
- id: end-of-file-fixer
- id: mixed-line-ending
- repo: https://github.com/JoC0de/pre-commit-prettier
rev: fc2da0552b28c24c836d045bfb6c3057b3d11e62 # v3.9.4
hooks:
- id: prettier
files: \.(ya?ml|toml)$
# https://prettier.io/docs/en/options.html#print-width
args: ["--print-width=120"]
- repo: https://github.com/tox-dev/pyproject-fmt
rev: v2.25.1
hooks:
- id: pyproject-fmt
additional_dependencies:
- "tomli>=2.0.1"
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.25
hooks:
- id: validate-pyproject
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.20
hooks:
- id: ruff-check
args: ["--fix"]
- id: ruff-format
types_or: [python, pyi, jupyter]
- repo: https://github.com/executablebooks/mdformat
rev: 1.0.0
hooks:
- id: mdformat
additional_dependencies:
- "mdformat-mkdocs[recommended]>=2.1.0"
- "mdformat-ruff"
args: ["--number", "--wrap=no"]
exclude: ^(docs/changelog\.md|docs/deprecated\.md)$
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v2.1.0
hooks:
- id: mypy
language_version: python3.11
additional_dependencies:
- "numpy>=2.0"
- "types-PyYAML"
- "types-requests"
- "types-tqdm"
- repo: https://github.com/codespell-project/codespell
rev: v2.4.2
hooks:
- id: codespell
additional_dependencies:
- "tomli>=2.0.1"
+153
View File
@@ -0,0 +1,153 @@
# Agent Guidelines for `supervision`
Behave like a senior contributor: precise, efficient, maintainable. When this file and [CONTRIBUTING.md](.github/CONTRIBUTING.md) conflict, **CONTRIBUTING.md wins**.
---
## 1. Before You Code
- Read the task thoroughly; group clarifications into one ask.
- Outline a plan before making changes.
- Check whether the feature already exists under a different name.
- Confirm alignment with `src/supervision/` architecture.
---
## 2. Repository Architecture
**Package root**: `src/supervision/` — all library code. **Tests**: `tests/` — mirrors `src/supervision/`. **Public API**: `src/supervision/__init__.py`.
```
src/supervision/
├── detection/
│ ├── core.py — Detections dataclass; all model connectors as classmethods
│ ├── compact_mask.py — compact mask representation
│ ├── vlm.py — VLM connectors (Florence-2, Gemini, Qwen, PaliGemma)
│ ├── utils/ — pure NumPy helpers: boxes, converters, iou_and_nms, masks, polygons
│ ├── line_zone.py — LineZone
│ └── tools/ — InferenceSlicer, PolygonZone, CSVSink, JSONSink, DetectionsSmoother
├── annotators/core.py — BoxAnnotator, MaskAnnotator, LabelAnnotator, … each: .annotate(scene, detections)
├── key_points/ — KeyPoints, EdgeAnnotator, VertexAnnotator (use this, NOT keypoint/ — see §4)
├── tracker/ — DEPRECATED
├── dataset/core.py — DetectionDataset / ClassificationDataset (YOLO / COCO / Pascal VOC)
├── geometry/core.py — Point, Rect, Vector, Position
├── metrics/ — mAP, confusion matrix (requires --extra metrics)
├── utils/internal.py — warn_deprecated, deprecated_parameter, internal helpers
└── config.py — string constants; always import from here, never use literals
```
### Key design patterns
- **`Detections` is the lingua franca** — every connector, tracker, and annotator speaks `Detections`. New connector = `@classmethod from_<framework>(cls, result) -> Detections`.
- **Annotators are composable** — receive `scene` (BGR `np.ndarray`) + `detections`, return annotated copy.
- **`data` dict extensibility** — per-detection metadata in `detections.data` as `np.ndarray` aligned with `xyxy`. Keys are constants from `config.py`.
- **Vectorized throughout** — NumPy arrays, no Python loops in hot paths. Never write `for det in detections`.
- **Lazy-import heavy deps** — `torch`, `transformers`, `ultralytics` must be imported inside the function that needs them, never at module top level.
---
## 3. Agent-Critical Rules
These supplement [CONTRIBUTING.md](.github/CONTRIBUTING.md) — covering gaps or agent-specific failure modes.
**Doc headings**: `###` max in docstrings and docs. `####` renders identically to bold in mkdocs — use `**bold**` instead.
**Type hints**: required on all new code. mypy is enforced by pre-commit (`.pre-commit-config.yaml`).
**Function docstrings**: every new or modified function, including private helpers and tests, must have a succinct docstring explaining its purpose. Put function-level why/what/how context inside the function docstring, not in a comment before the function. Public APIs still require the full Google-style structure described below.
**Readable argument lists**: do not put multi-branch conditional expressions inside function or constructor arguments. If an argument needs more than a simple `a if condition else b`, assign it to a named local variable before the call.
**Inline comments**: write code so the intent is clear from names, small helpers, and straightforward control flow. For non-trivial logic inside a function that still needs context, add concise inline comments explaining why the code exists, what invariant it protects, and how the tricky part works. Do not put comments before functions; use the function docstring instead. Do not comment obvious assignments, mechanical plumbing, lint-only changes, typing-only changes, or pure docs edits.
**Doctest determinism** — output must be reproducible across platforms:
- Use `# doctest: +ELLIPSIS` for floats that vary by platform.
- Seed any RNG before calling it.
- Never assert `dict` or `set` iteration order.
- No network or filesystem access outside `supervision/assets/`.
**⚠ Test structure** — agents frequently fail here; read [CONTRIBUTING.md §Tests](.github/CONTRIBUTING.md#-tests) carefully: AAA structure, class grouping, parametrize with `pytest.param(..., id="slug")`, one-line docstring per test.
For branching, commit, code style, and API design conventions see [CONTRIBUTING.md](.github/CONTRIBUTING.md).
---
## 4. Deprecated Module Aliases
`supervision.keypoint` deprecated since `0.27.0`, removed in `0.31.0`. Always import from `supervision.key_points`, not `supervision.keypoint`.
---
## 5. Deprecating APIs
**Minimum window**: deprecated APIs must remain for at least **3 minor releases** before removal. Example: deprecated in `0.29.0` → removed in `0.32.0`.
- Module-level: `supervision.utils.internal.warn_deprecated` in the deprecated module's own `__init__.py`
- Parameter renamed (old→new): `supervision.utils.internal.deprecated_parameter` decorator
- Public function, method, or class: `@deprecated` from `pydeprecate`
Always name the version introduced and the removal version:
```python
warn_deprecated("'foo' deprecated in `0.29.0`, removed in `0.32.0`. Use 'bar'.")
```
---
## 6. Implementing Features
- Minimal implementation; type hints and Google docstrings with usage examples.
- Tests covering new functionality and edge cases (see [CONTRIBUTING.md §Tests](.github/CONTRIBUTING.md#-tests)).
- Update docstrings and mkdocs entries as needed.
- Update [docs/changelog.md](docs/changelog.md) for every functional change or bug fix, including user-visible behavior changes. Skip changelog entries for lint-only, type-only, formatting-only, and pure documentation-only changes.
**Extending `Detections`**: store metadata in `detections.data` as `np.ndarray` aligned with `xyxy`; define the key as a constant in `config.py` (e.g. `CLASS_NAME_DATA_FIELD`, `ORIENTED_BOX_COORDINATES`).
**New model connector** (`detection/core.py`):
```python
@classmethod
def from_myframework(cls, result) -> "Detections":
import myframework # noqa: F401 — lazy import
xyxy = ... # (N, 4)
return cls(
xyxy=xyxy,
confidence=...,
class_id=...,
data={CLASS_NAME_DATA_FIELD: np.array([...])},
)
```
VLM connectors go in `detection/vlm.py`, not `core.py`.
---
## 7. Bugs & Refactoring
**Bugs**: reproduce → write failing test → minimal fix → verify no regressions.
**Refactoring**: preserve behavior and API; reduce duplication; avoid sweeping changes unless requested; apply §5 deprecation when removing public API.
---
## 8. Before You Commit
```bash
uv run pytest --cov=supervision
uv run pre-commit run --all-files
```
Capture a baseline before changes to avoid introducing new failures:
```bash
STASH_BEFORE=$(git rev-parse refs/stash 2>/dev/null)
git stash push --include-untracked
uv run pytest -q 2>&1 | tee /tmp/baseline.txt
[ "$(git rev-parse refs/stash 2>/dev/null)" != "$STASH_BEFORE" ] && git stash pop
uv run pytest -q 2>&1 | tee /tmp/after.txt
diff /tmp/baseline.txt /tmp/after.txt
```
Any test passing in baseline but failing after = blocker.
+23
View File
@@ -0,0 +1,23 @@
# This CITATION.cff file was generated with cffinit.
# Visit https://bit.ly/cffinit to generate yours today!
cff-version: 1.2.0
title: Supervision
message: >-
If you use this software, please cite it using the
metadata from this file.
type: software
authors:
- given-names: Roboflow
email: support@roboflow.com
repository-code: 'https://github.com/roboflow/supervision'
url: 'https://roboflow.github.io/supervision/'
abstract: >-
supervision features a range of utilities for use in
computer vision projects, from detections processing and
filtering to confusion matrix calculation.
keywords:
- computer vision
- image processing
- video processing
license: MIT
+5
View File
@@ -0,0 +1,5 @@
# Claude Code Project Instructions
<!-- Imports AGENTS.md, which contains agent roles, behavioral rules, and coding constraints for this project. -->
@AGENTS.md
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2022 Roboflow
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+321
View File
@@ -0,0 +1,321 @@
<div align="center">
<p>
<a align="center" href="https://supervision.roboflow.com" target="_blank">
<img
width="100%"
src="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png?updatedAt=1678995927529"
>
</a>
</p>
<br>
[notebooks](https://github.com/roboflow/notebooks) | [inference](https://github.com/roboflow/inference) | [autodistill](https://github.com/autodistill/autodistill) | [maestro](https://github.com/roboflow/multimodal-maestro)
<br>
[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision) [![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision) [![license](https://img.shields.io/pypi/l/supervision)](LICENSE.md) [![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision) [![codecov](https://codecov.io/gh/roboflow/supervision/graph/badge.svg?token=HMNJ5FVZ36)](https://codecov.io/gh/roboflow/supervision)
[![snyk](https://snyk.io/advisor/python/supervision/badge.svg)](https://snyk.io/advisor/python/supervision) [![colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/main/demo.ipynb) [![gradio](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/Roboflow/Annotators) [![discord](https://img.shields.io/discord/1159501506232451173?logo=discord&label=discord&labelColor=fff&color=5865f2&link=https%3A%2F%2Fdiscord.gg%2FGbfgXGJ8Bk)](https://discord.gg/GbfgXGJ8Bk)
<div align="center">
<a href="https://trendshift.io/repositories/124" target="_blank"><img src="https://trendshift.io/api/badge/repositories/124" alt="roboflow%2Fsupervision | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</div>
</div>
<details>
<summary><strong>📑 Table of Contents</strong></summary>
- [👋 Hello](#-hello)
- [💻 Install](#-install)
- [🔥 Quickstart](#-quickstart)
- [Models](#models)
- [Annotators](#annotators)
- [Datasets](#datasets)
- [🎬 Tutorials](#-tutorials)
- [💜 Built with Supervision](#-built-with-supervision)
- [📚 Documentation](#-documentation)
- [🏆 Contribution](#-contribution)
</details>
## 👋 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**](https://www.python.org/) environment.
```bash
pip install supervision
```
Read more about conda, mamba, and installing from source in our [guide](https://roboflow.github.io/supervision/).
## 🔥 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](https://supervision.roboflow.com/latest/detection/core/#detections) 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`.
```python
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
```
<details>
<summary>👉 more model connectors</summary>
- inference
Running with [Inference](https://github.com/roboflow/inference) requires a [Roboflow API KEY](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key).
```python
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
```
</details>
### Annotators
Supervision offers a wide range of highly customizable [annotators](https://supervision.roboflow.com/latest/detection/annotators/), allowing you to compose the perfect visualization for your use case.
```python
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](https://supervision.roboflow.com/latest/datasets/core/) that allow you to load, split, merge, and save datasets in one of the supported formats.
```python
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
```
<details>
<summary>👉 more dataset utils</summary>
- load
```python
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
```python
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
```python
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
```python
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
```python
sv.DetectionDataset.from_yolo(
images_directory_path=...,
annotations_directory_path=...,
data_yaml_path=...,
).as_pascal_voc(
images_directory_path=...,
annotations_directory_path=...,
)
```
</details>
## 🎬 Tutorials
Want to learn how to use Supervision? Explore our [how-to guides](https://supervision.roboflow.com/develop/how_to/detect_and_annotate/), [end-to-end examples](./examples), [cheatsheet](https://roboflow.github.io/cheatsheet-supervision/), and [cookbooks](https://supervision.roboflow.com/develop/cookbooks/)!
<br/>
<p align="left">
<a href="https://youtu.be/hAWpsIuem10" title="Dwell Time Analysis with Computer Vision | Real-Time Stream Processing"><img src="https://github.com/user-attachments/assets/014cffc7-72b3-4c0a-bb89-6de265b2c06b" alt="Dwell Time Analysis with Computer Vision | Real-Time Stream Processing" width="300px" align="left" /></a>
<a href="https://youtu.be/hAWpsIuem10" title="Dwell Time Analysis with Computer Vision | Real-Time Stream Processing"><strong>Dwell Time Analysis with Computer Vision | Real-Time Stream Processing</strong></a>
<div><strong>Created: 5 Apr 2024</strong></div>
<br/>Learn how to use computer vision to analyze wait times and optimize processes. This tutorial covers object detection, tracking, and calculating time spent in designated zones. Use these techniques to improve customer experience in retail, traffic management, or other scenarios.</p>
<br/>
<p align="left">
<a href="https://youtu.be/uWP6UjDeZvY" title="Speed Estimation & Vehicle Tracking | Computer Vision | Open Source"><img src="https://github.com/user-attachments/assets/b16b8e21-dc6c-4a73-a678-2f7d5d374793" alt="Speed Estimation & Vehicle Tracking | Computer Vision | Open Source" width="300px" align="left" /></a>
<a href="https://youtu.be/uWP6UjDeZvY" title="Speed Estimation & Vehicle Tracking | Computer Vision | Open Source"><strong>Speed Estimation & Vehicle Tracking | Computer Vision | Open Source</strong></a>
<div><strong>Created: 11 Jan 2024</strong></div>
<br/>Learn how to track and estimate the speed of vehicles using YOLO, ByteTrack, and Roboflow Inference. This comprehensive tutorial covers object detection, multi-object tracking, filtering detections, perspective transformation, speed estimation, visualization improvements, and more.</p>
## 💜 Built with Supervision
Did you build something cool using supervision? [Let us know!](https://github.com/roboflow/supervision/discussions/categories/built-with-supervision)
https://user-images.githubusercontent.com/26109316/207858600-ee862b22-0353-440b-ad85-caa0c4777904.mp4
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](https://roboflow.github.io/supervision) 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](.github/CONTRIBUTING.md) to get started. Thank you 🙏 to all our contributors!
<p align="center">
<a href="https://github.com/roboflow/supervision/graphs/contributors">
<img src="https://contrib.rocks/image?repo=roboflow/supervision" />
</a>
</p>
<br>
<div align="center">
<a href="https://youtube.com/roboflow">
<img
src="https://media.roboflow.com/notebooks/template/icons/purple/youtube.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949634652"
width="3%"
/>
</a>
<img src="https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png" width="3%"/>
<a href="https://roboflow.com">
<img
src="https://media.roboflow.com/notebooks/template/icons/purple/roboflow-app.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949746649"
width="3%"
/>
</a>
<img src="https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png" width="3%"/>
<a href="https://www.linkedin.com/company/roboflow-ai/">
<img
src="https://media.roboflow.com/notebooks/template/icons/purple/linkedin.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633691"
width="3%"
/>
</a>
<img src="https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png" width="3%"/>
<a href="https://docs.roboflow.com">
<img
src="https://media.roboflow.com/notebooks/template/icons/purple/knowledge.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949634511"
width="3%"
/>
</a>
<img src="https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png" width="3%"/>
<a href="https://discuss.roboflow.com">
<img
src="https://media.roboflow.com/notebooks/template/icons/purple/forum.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633584"
width="3%"
/>
</a>
<img src="https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png" width="3%"/>
<a href="https://blog.roboflow.com">
<img
src="https://media.roboflow.com/notebooks/template/icons/purple/blog.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633605"
width="3%"
/>
</a>
</div>
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`roboflow/supervision`
- 原始仓库:https://github.com/roboflow/supervision
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
Vendored
+1481
View File
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
0d5d9799b1cc4a39825146388c6781eb
+1
View File
@@ -0,0 +1 @@
supervision.roboflow.com
+6
View File
@@ -0,0 +1,6 @@
/*
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; img-src 'self' https: data:; media-src 'self' https: data:; font-src 'self' https: data:; style-src 'self'; script-src 'self'; connect-src 'self' https:;
+27
View File
@@ -0,0 +1,27 @@
---
comments: true
description: About Supervision, Roboflow's open-source Python library for building reusable computer vision workflows.
---
# About Supervision
Supervision is an open-source Python library by Roboflow for building computer vision applications. It gives developers a model-agnostic toolkit for loading predictions, annotating images and video, tracking objects, counting detections in zones, processing datasets, and evaluating model performance.
The project centers on a unified `Detections` API with converters for supported outputs from Ultralytics, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers such as Florence-2, PaliGemma, Qwen VL, Gemini, DeepSeek VL 2, and Moondream. That common representation lets teams change models without rewriting annotation, filtering, tracking, dataset, or metrics code.
Supervision is maintained by Roboflow and an open-source contributor community. The library is MIT licensed, developed in public on GitHub, and published on PyPI.
## Project Links
- Source code: [github.com/roboflow/supervision](https://github.com/roboflow/supervision)
- Package: [pypi.org/project/supervision](https://pypi.org/project/supervision/)
- Community: [Roboflow Discord](https://discord.gg/GbfgXGJ8Bk)
- Roboflow: [roboflow.com](https://roboflow.com/)
## Maintainers and Contributors
Supervision has been shaped by Roboflow engineers and community contributors, including Piotr Skalski, Borda, onuralpszr, Soumik Mandal, and many others. The complete contributor history is available in the GitHub repository.
## Citation
If Supervision helps your research or production system, cite the project using the citation block in [llms.txt](https://supervision.roboflow.com/llms.txt) or link to the GitHub repository.
+26
View File
@@ -0,0 +1,26 @@
---
comments: true
description: API reference for supervision's assets module — download sample video and image files for demos, testing, and tutorials.
---
# Assets
Supervision offers an assets download utility that allows you to download image and video files that you can use in your demos.
<div class="md-typeset">
<h2><a href="#supervision.assets.downloader.download_assets.download_assets">download_assets</a></h2>
</div>
:::supervision.assets.downloader.download_assets
<div class="md-typeset">
<h2><a href="#supervision.assets.downloader.download_assets.VideoAssets">VideoAssets</a></h2>
</div>
:::supervision.assets.list.VideoAssets
<div class="md-typeset">
<h2><a href="#supervision.assets.list.ImageAssets">ImageAssets</a></h2>
</div>
:::supervision.assets.list.ImageAssets
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 600 600" style="enable-background:new 0 0 600 600;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#6706CE;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
</style>
<g>
<circle class="st0" cx="300" cy="300" r="300"/>
</g>
<g>
<path class="st1" d="M279.34,267.67c27.7-21.58,15.55-51.11-30.24-45.4c-53.03,6.6-120.62,58.45-137.46,120.7
c-1.38,5.09-2.45,10.27-3.19,15.5c-0.73,5.15-1.12,10.35-1.17,15.55c-0.05,5.15,0.25,10.3,0.89,15.4
c0.64,5.11,1.64,10.17,2.98,15.14c1.36,5.03,3.06,9.97,5.09,14.76c2.09,4.92,4.51,9.68,7.24,14.26c2.83,4.76,5.98,9.31,9.4,13.64
c11.67,14.78,26.65,27.16,42.63,37.02c3.46,2.14,7.18,4.21,11.25,4.41c5.94,0.28,10.44-4.44,10.68-10.23
c0.09-2.18-0.46-4.24-1.46-6c-13.42-23.67-24.52-58.81-22.24-80.99C179.43,336.29,235.28,301.98,279.34,267.67z"/>
<path class="st1" d="M500.28,363.84c-2.9-6.91-10.16-10.81-17.51-10.15c-5.02,0.45-9.17,3.13-12.55,6.68
c-5.49,4.97-9.31,11.89-13.43,17.91c-4.86,7.08-9.94,14.02-15.41,20.63c-10.8,13.04-23.24,24.79-37.76,33.61
c-24.63,14.95-47.17,22.12-74.27,8.31c-19.83-15.86-13.13-34.6,3.29-49.87c28.08-26.1,61.93-44.42,88.52-72.44
c25-26.34,47.05-59.11,52.24-95.78c1.46-10.27,1.48-20.74-0.17-31c-7.8-48.31-51.48-78.97-95.59-92.01
C321.47,83.13,259.6,88,206.48,112.56c-21.86,10.11-42.23,23.65-59.94,39.98c-7.85,7.24-15.24,15.01-22.1,23.2
c-11.1,13.27-23.73,28.77-25.89,46.57c-1.33,10.99,8.58,18.59,18.99,17.18c6.98-0.94,13.16-5.15,18.3-9.74
c5.97-5.33,11.45-11.25,17.21-16.82c17.38-16.82,35.94-32.47,58.01-42.79c28.11-13.15,59.61-19.55,90.6-16.32
c31.43,3.27,69.67,17.44,81.15,49.98c11.97,33.97-13.73,67.36-37.18,89.06c-38.29,35.44-110.99,71.63-102.98,134.19
c4.29,33.51,28.4,62.19,59.24,74.96c53.66,22.23,111.74-4.84,148.89-46.18c12.46-13.24,30.38-35.82,46.68-69.46
C500.61,379.84,503.23,370.87,500.28,363.84z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 600 600" style="enable-background:new 0 0 600 600;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#6706CE;}
</style>
<g>
<circle class="st0" cx="300" cy="300" r="300"/>
</g>
<g>
<path class="st1" d="M279.34,267.67c27.7-21.58,15.55-51.11-30.24-45.4c-53.03,6.6-120.62,58.45-137.46,120.7
c-1.38,5.09-2.45,10.27-3.19,15.5c-0.73,5.15-1.12,10.35-1.17,15.55c-0.05,5.15,0.25,10.3,0.89,15.4
c0.64,5.11,1.64,10.17,2.98,15.14c1.36,5.03,3.06,9.97,5.09,14.76c2.09,4.92,4.51,9.68,7.24,14.26c2.83,4.76,5.98,9.31,9.4,13.64
c11.67,14.78,26.65,27.16,42.63,37.02c3.46,2.14,7.18,4.21,11.25,4.41c5.94,0.28,10.44-4.44,10.68-10.23
c0.09-2.18-0.46-4.24-1.46-6c-13.42-23.67-24.52-58.81-22.24-80.99C179.43,336.29,235.28,301.98,279.34,267.67z"/>
<path class="st1" d="M500.28,363.84c-2.9-6.91-10.16-10.81-17.51-10.15c-5.02,0.45-9.17,3.13-12.55,6.68
c-5.49,4.97-9.31,11.89-13.43,17.91c-4.86,7.08-9.94,14.02-15.41,20.63c-10.8,13.04-23.24,24.79-37.76,33.61
c-24.63,14.95-47.17,22.12-74.27,8.31c-19.83-15.86-13.13-34.6,3.29-49.87c28.08-26.1,61.93-44.42,88.52-72.44
c25-26.34,47.05-59.11,52.24-95.78c1.46-10.27,1.48-20.74-0.17-31c-7.8-48.31-51.48-78.97-95.59-92.01
C321.47,83.13,259.6,88,206.48,112.56c-21.86,10.11-42.23,23.65-59.94,39.98c-7.85,7.24-15.24,15.01-22.1,23.2
c-11.1,13.27-23.73,28.77-25.89,46.57c-1.33,10.99,8.58,18.59,18.99,17.18c6.98-0.94,13.16-5.15,18.3-9.74
c5.97-5.33,11.45-11.25,17.21-16.82c17.38-16.82,35.94-32.47,58.01-42.79c28.11-13.15,59.61-19.55,90.6-16.32
c31.43,3.27,69.67,17.44,81.15,49.98c11.97,33.97-13.73,67.36-37.18,89.06c-38.29,35.44-110.99,71.63-102.98,134.19
c4.29,33.51,28.4,62.19,59.24,74.96c53.66,22.23,111.74-4.84,148.89-46.18c12.46-13.24,30.38-35.82,46.68-69.46
C500.61,379.84,503.23,370.87,500.28,363.84z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 600 600" style="enable-background:new 0 0 600 600;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
</style>
<path class="st0" d="M300,0C134.31,0,0,134.31,0,300s134.31,300,300,300s300-134.31,300-300S465.69,0,300,0z M195.98,472.42
c1,1.76,1.55,3.82,1.46,6c-0.24,5.79-4.74,10.51-10.68,10.23c-4.07-0.19-7.78-2.27-11.25-4.41c-15.98-9.86-30.96-22.24-42.63-37.02
c-3.42-4.33-6.57-8.89-9.4-13.64c-2.72-4.58-5.15-9.34-7.24-14.26c-2.03-4.79-3.74-9.72-5.09-14.76
c-1.34-4.97-2.33-10.03-2.98-15.14c-0.64-5.1-0.94-10.25-0.89-15.4c0.05-5.2,0.45-10.4,1.17-15.55c0.74-5.23,1.81-10.41,3.19-15.5
c16.84-62.24,84.43-114.09,137.46-120.7c45.79-5.71,57.94,23.81,30.24,45.4c-44.06,34.32-99.92,68.63-105.6,123.77
C171.46,413.61,182.55,448.75,195.98,472.42z M497.44,386.39c-16.3,33.65-34.22,56.22-46.68,69.46
c-37.14,41.34-95.23,68.4-148.89,46.18c-30.83-12.77-54.94-41.45-59.24-74.96c-8.02-62.55,64.69-98.74,102.98-134.19
c23.45-21.71,49.16-55.1,37.18-89.06c-11.47-32.55-49.72-46.71-81.15-49.98c-30.99-3.23-62.49,3.17-90.6,16.32
c-22.07,10.32-40.62,25.97-58.01,42.79c-5.75,5.57-11.24,11.49-17.21,16.82c-5.14,4.59-11.31,8.79-18.29,9.74
c-10.41,1.41-20.32-6.18-18.99-17.18c2.16-17.8,14.79-33.29,25.89-46.57c6.86-8.19,14.25-15.96,22.1-23.2
c17.71-16.34,38.08-29.87,59.94-39.98C259.6,88,321.47,83.13,377.64,99.73c44.11,13.04,87.79,43.7,95.59,92.01
c1.65,10.25,1.63,20.72,0.17,31c-5.19,36.67-27.24,69.44-52.24,95.78c-26.59,28.02-60.44,46.35-88.52,72.44
c-16.43,15.27-23.13,34.01-3.29,49.87c27.1,13.81,49.64,6.64,74.27-8.31c14.52-8.82,26.96-20.57,37.76-33.61
c5.48-6.61,10.56-13.55,15.41-20.63c4.13-6.02,7.94-12.94,13.43-17.91c3.38-3.55,7.53-6.23,12.55-6.68
c7.35-0.66,14.61,3.23,17.51,10.15C503.23,370.87,500.61,379.84,497.44,386.39z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+1801
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
---
comments: true
---
# Classifications
:::supervision.classification.core.Classifications
+1
View File
@@ -0,0 +1 @@
--8<-- ".github/CODE_OF_CONDUCT.md"
+29
View File
@@ -0,0 +1,29 @@
---
comments: true
description: Contact and support channels for Supervision documentation, bugs, feature requests, security reports, and community help.
---
# Contact
Use the channel that matches the kind of request you have.
## Bugs and Feature Requests
Open a GitHub issue for reproducible bugs, API requests, documentation fixes, and feature proposals:
[github.com/roboflow/supervision/issues](https://github.com/roboflow/supervision/issues)
## Community Support
Join the Roboflow Discord for community questions, examples, and implementation discussion:
[discord.gg/GbfgXGJ8Bk](https://discord.gg/GbfgXGJ8Bk)
## Package and Source
- PyPI package: [pypi.org/project/supervision](https://pypi.org/project/supervision/)
- GitHub repository: [github.com/roboflow/supervision](https://github.com/roboflow/supervision)
## Security Reports
For security-sensitive reports, avoid posting public exploit details in an issue. Use GitHub's private vulnerability reporting flow for the repository when available, or contact Roboflow through the security and support channels listed on [roboflow.com](https://roboflow.com/).
+1
View File
@@ -0,0 +1 @@
--8<-- ".github/CONTRIBUTING.md"
+8
View File
@@ -0,0 +1,8 @@
---
template: cookbooks.html
comments: true
description: Collection of practical computer vision cookbooks — object tracking, zero-shot detection, SAHI small object detection, occupancy analytics, and more.
hide:
- navigation
- toc
---
+22
View File
@@ -0,0 +1,22 @@
---
comments: true
description: API reference for supervision's DetectionDataset and ClassificationDataset — load, merge, split, and convert datasets in YOLO, COCO, VOC, CreateML, and LabelMe formats.
---
# Datasets
!!! warning
Dataset API is still fluid and may change. If you use Dataset API in your project until further notice, freeze the `supervision` version in your `requirements.txt` or `setup.py`.
<div class="md-typeset">
<h2>DetectionDataset</h2>
</div>
:::supervision.dataset.core.DetectionDataset
<div class="md-typeset">
<h2>ClassificationDataset</h2>
</div>
:::supervision.dataset.core.ClassificationDataset
+54
View File
@@ -0,0 +1,54 @@
---
comments: true
status: deprecated
---
# Deprecated
These features are phased out due to better alternatives or potential issues in future versions. Deprecated functionalities are typically supported for multiple subsequent releases, providing time for users to transition to updated methods.
- [`sv.ByteTrack`](https://supervision.roboflow.com/latest/trackers/#supervision.tracker.byte_tracker.core.ByteTrack) is deprecated in `supervision-0.28.0` in favour of `ByteTrackTracker` from the external [`trackers`](https://pypi.org/project/trackers/) package (`pip install trackers`). The update method is renamed from `update_with_detections()` to `update()`. Removal is planned for `supervision-0.31.0`.
- `supervision.keypoint` module is deprecated in `supervision-0.27.0`; use `supervision.key_points` instead. It will be removed in `supervision-0.31.0`.
- `create_tiles` in `supervision.utils.image` is deprecated in `supervision-0.27.0`. It will be removed in `supervision-0.31.0`.
- `ensure_cv2_image_for_processing` in `supervision.utils.conversion` is deprecated in `supervision-0.27.0`. It will be removed in `supervision-0.31.0`.
- Keypoint validation utilities in `supervision.validators` are deprecated in `supervision-0.27.0`. They will be removed in `supervision-0.31.0`.
- `normalized_xyxy` argument in [`sv.denormalize_boxes`](https://supervision.roboflow.com/latest/detection/utils/boxes/#supervision.detection.utils.boxes.denormalize_boxes) is deprecated in `supervision-0.27.0` and renamed to `xyxy`. Passing `normalized_xyxy=` emits a `FutureWarning`; support will be removed in `supervision-0.31.0`.
- `supervision.dataset.utils` import path for [`sv.rle_to_mask`](https://supervision.roboflow.com/latest/detection/utils/converters/#supervision.detection.utils.converters.rle_to_mask) and [`sv.mask_to_rle`](https://supervision.roboflow.com/latest/detection/utils/converters/#supervision.detection.utils.converters.mask_to_rle) is deprecated in `supervision-0.28.0`. These functions moved to `supervision.detection.utils.converters` and will be removed from `supervision.dataset.utils` in `supervision-0.31.0`.
- `sv.LMM` enum is deprecated in `supervision-0.27.0` and will be removed in `supervision-0.31.0`. Use `sv.VLM` instead.
- [`sv.Detections.from_lmm`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_lmm) classmethod is deprecated in `supervision-0.26.0` and will be removed in `supervision-0.31.0`. Use [`sv.Detections.from_vlm`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_vlm) instead.
- `KeyPoints.confidence` is deprecated in `supervision-0.29.0`. Use `KeyPoints.keypoint_confidence` instead. It will be removed in `supervision-0.32.0`.
- Public `validate_*` helper functions are deprecated in `supervision-0.29.0` and will be removed in `supervision-0.32.0`. Supervision internals now use private `_validate_*` helpers.
# Removed
### 0.27.0
- `overlap_ratio_wh` parameter in [`sv.InferenceSlicer`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/) has been removed. Use the pixel-based `overlap_wh` parameter instead.
- `overlap_filter_strategy` parameter in [`sv.InferenceSlicer`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/) has been removed. Use `overlap_strategy` instead.
### 0.26.0
- The `sv.DetectionDataset.images` property has been removed in `supervision-0.26.0`. Please loop over images with `for path, image, annotation in dataset:`, as that does not require loading all images into memory. Also, constructing `sv.DetectionDataset` with parameter `images` as `Dict[str, np.ndarray]` is deprecated and has been removed in `supervision-0.26.0`. Please pass a list of paths `List[str]` instead.
- The name `sv.BoundingBoxAnnotator` is deprecated and has been removed in `supervision-0.26.0`. It has been renamed to [`sv.BoxAnnotator`](https://supervision.roboflow.com/0.22.0/detection/annotators/#supervision.annotators.core.BoxAnnotator).
### 0.24.0
- The `frame_resolution_wh ` parameter in [`sv.PolygonZone`](detection/tools/polygon_zone.md/#supervision.detection.tools.polygon_zone.PolygonZone) has been removed.
- Supervision installation methods `"headless"` and `"desktop"` were removed, as they are no longer needed. `pip install supervision[headless]` will install the base library and harmlessly warn of non-existent extras.
### 0.23.0
- The `track_buffer`, `track_thresh`, and `match_thresh` parameters in [`ByteTrack`](trackers.md/#supervision.tracker.byte_tracker.core.ByteTrack) are deprecated and were removed as of `supervision-0.23.0`. Use `lost_track_buffer,` `track_activation_threshold`, and `minimum_matching_threshold` instead.
- The `triggering_position ` parameter in [`sv.PolygonZone`](detection/tools/polygon_zone.md/#supervision.detection.tools.polygon_zone.PolygonZone) was removed as of `supervision-0.23.0`. Use `triggering_anchors` instead.
### 0.22.0
- `sv.Detections.from_roboflow` is removed as of `supervision-0.22.0`. Use [`Detections.from_inference`](detection/core.md/#supervision.detection.core.Detections.from_inference) instead.
- The method `sv.Color.white()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.WHITE` instead.
- The method `sv.Color.black()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.BLACK` instead.
- The method `sv.Color.red()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.RED` instead.
- The method `sv.Color.green()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.GREEN` instead.
- The method `sv.Color.blue()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.BLUE` instead.
- The method `sv.ColorPalette.default()` was removed as of `supervision-0.22.0`. Use the constant [`ColorPalette.DEFAULT`](utils/draw.md/#supervision.draw.color.ColorPalette.DEFAULT) instead.
- `sv.BoxAnnotator` was removed as of `supervision-0.22.0`, however `sv.BoundingBoxAnnotator` was immediately renamed to `sv.BoxAnnotator`. Use [`BoxAnnotator`](detection/annotators.md/#supervision.annotators.core.BoxAnnotator) and [`LabelAnnotator`](detection/annotators.md/#supervision.annotators.core.LabelAnnotator) instead of the old `sv.BoxAnnotator`.
- The method `sv.FPSMonitor.__call__` was removed as of `supervision-0.22.0`. Use the attribute [`sv.FPSMonitor.fps`](utils/video.md/#supervision.utils.video.FPSMonitor.fps) instead.
+685
View File
@@ -0,0 +1,685 @@
---
comments: true
description: API reference for supervision's annotator classes — draw bounding boxes, masks, labels, tracks, and heatmaps on images with one method call.
---
# Annotators
Annotators accept detections and apply box or mask visualizations to the detections. Annotators have many available styles.
=== "Outlines"
=== "Box"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
box_annotator = sv.BoxAnnotator()
annotated_frame = box_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![bounding-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/bounding-box-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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,
)
```
<div class="result" markdown>
![round-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/round-box-annotator-example-purple.png){ align=center width="800" }
</div>
=== "BoxCorner"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
corner_annotator = sv.BoxCornerAnnotator()
annotated_frame = corner_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![box-corner-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-corner-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Circle"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
circle_annotator = sv.CircleAnnotator()
annotated_frame = circle_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![circle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/circle-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Ellipse"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
ellipse_annotator = sv.EllipseAnnotator()
annotated_frame = ellipse_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ellipse-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Polygon"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
polygon_annotator = sv.PolygonAnnotator()
annotated_frame = polygon_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![polygon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/polygon-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Shading"
=== "Color"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
color_annotator = sv.ColorAnnotator()
annotated_frame = color_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![box-mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-mask-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Halo"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
halo_annotator = sv.HaloAnnotator()
annotated_frame = halo_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![halo-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Mask"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
mask_annotator = sv.MaskAnnotator()
annotated_frame = mask_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
!!! note
`MaskAnnotator` expects `detections.mask` to contain instance segmentation masks aligned to the image passed to `annotate`. For dense masks, provide a boolean array of shape `(N, H, W)` where `(H, W)` matches the image height and width (it also accepts `sv.CompactMask`). If your model returns framework-specific results, convert them to `sv.Detections` first, for example with `sv.Detections.from_ultralytics(...)` or `sv.Detections.from_inference(...)`.
<div class="result" markdown>
![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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,
)
```
<div class="result" markdown>
![dot-annotator-example](https://media.roboflow.com/supervision-annotator-examples/dot-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Triangle"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
triangle_annotator = sv.TriangleAnnotator()
annotated_frame = triangle_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![triangle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/triangle-annotator-example.png){ align=center width="800" }
</div>
=== "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,
)
]
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
annotated_frame = label_annotator.annotate(
scene=image.copy(), detections=detections, labels=labels
)
```
<div class="result" markdown>
![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" }
</div>
=== "RichLabel"
```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,
)
]
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,
)
```
<div class="result" markdown>
![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Transformative"
=== "Blur"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
blur_annotator = sv.BlurAnnotator()
annotated_frame = blur_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Pixelate"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
pixelate_annotator = sv.PixelateAnnotator()
annotated_frame = pixelate_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![pixelate-annotator-example](https://media.roboflow.com/supervision-annotator-examples/pixelate-annotator-example-10.png){ align=center width="800" }
</div>
<!-- === "Crop"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
crop_annotator = sv.CropAnnotator()
annotated_frame = crop_annotator.annotate(
scene=image.copy(),
detections=detections,
)
```
<div class="result" markdown>
![crop-annotator-example](https://media.roboflow.com/supervision-annotator-examples/crop-annotator-example.png){ align=center width="800" }
</div>
-->
=== "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)
```
<div class="result" markdown>
![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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)
```
<div class="result" markdown>
![heat-map-annotator-example](https://media.roboflow.com/supervision-annotator-examples/heat-map-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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,
)
```
<div class="result" markdown>
![percentage-bar-annotator-example](https://media.roboflow.com/supervision-annotator-examples/percentage-bar-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Icon"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
icon_paths = ["<ICON_PATH>" for _ in detections]
icon_annotator = sv.IconAnnotator()
annotated_frame = icon_annotator.annotate(
scene=image.copy(),
detections=detections,
icon_path=icon_paths,
)
```
<div class="result" markdown>
![icon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/icon-annotator-example.png){ align=center width="800" }
</div>
=== "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,
)
```
<div class="result" markdown>
![background-overlay-annotator-example](https://media.roboflow.com/supervision-annotator-examples/background-color-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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,
)
```
<div class="result" markdown>
![comparison-annotator-example](https://media.roboflow.com/supervision-annotator-examples/comparison-annotator-example.png){ align=center width="800" }
</div>
<div class="md-typeset">
<h2>Try Supervision Annotators on your own image</h2>
Visualize annotators on images with COCO classes such as people, vehicles, animals, household items.
</div>
<div style="height: 400px; width: 100%; border-radius: 8px; overflow: hidden;"><iframe src="https://app.roboflow.com/workflows/embed/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3JrZmxvd0lkIjoiNDdtd2xuWW16S25VNWtOYUZjMG8iLCJ3b3Jrc3BhY2VJZCI6ImtyT1RBYm5jRmhvUU1DZExPbGU0IiwidXNlcklkIjoiRVJNUFBZY3FQMmZWWjB1NkRpNXZaYXJDdlZPMiIsImlhdCI6MTcyNjgzOTM2N30.gj2F6SnmmURAScJe4PTC1raUXsAK5mZyrUIGIJ44NhM?hideToolbar=true&hideHeader=true&defaultVisual=true" loading="lazy" title="Roboflow Workflow for Supervision Annotators" style="width: 100%; height: 100%; min-height: 400px; border: none;"></iframe></div>
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.BoxAnnotator">BoxAnnotator</a></h2>
</div>
:::supervision.annotators.core.BoxAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.RoundBoxAnnotator">RoundBoxAnnotator</a></h2>
</div>
:::supervision.annotators.core.RoundBoxAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.BoxCornerAnnotator">BoxCornerAnnotator</a></h2>
</div>
:::supervision.annotators.core.BoxCornerAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.OrientedBoxAnnotator">OrientedBoxAnnotator</a></h2>
</div>
:::supervision.annotators.core.OrientedBoxAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.ColorAnnotator">ColorAnnotator</a></h2>
</div>
:::supervision.annotators.core.ColorAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.CircleAnnotator">CircleAnnotator</a></h2>
</div>
:::supervision.annotators.core.CircleAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.DotAnnotator">DotAnnotator</a></h2>
</div>
:::supervision.annotators.core.DotAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.TriangleAnnotator">TriangleAnnotator</a></h2>
</div>
:::supervision.annotators.core.TriangleAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.EllipseAnnotator">EllipseAnnotator</a></h2>
</div>
:::supervision.annotators.core.EllipseAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.HaloAnnotator">HaloAnnotator</a></h2>
</div>
:::supervision.annotators.core.HaloAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.PercentageBarAnnotator">PercentageBarAnnotator</a></h2>
</div>
:::supervision.annotators.core.PercentageBarAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.HeatMapAnnotator">HeatMapAnnotator</a></h2>
</div>
:::supervision.annotators.core.HeatMapAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.MaskAnnotator">MaskAnnotator</a></h2>
</div>
:::supervision.annotators.core.MaskAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.PolygonAnnotator">PolygonAnnotator</a></h2>
</div>
:::supervision.annotators.core.PolygonAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.LabelAnnotator">LabelAnnotator</a></h2>
</div>
:::supervision.annotators.core.LabelAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.RichLabelAnnotator">RichLabelAnnotator</a></h2>
</div>
:::supervision.annotators.core.RichLabelAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.IconAnnotator">IconAnnotator</a></h2>
</div>
:::supervision.annotators.core.IconAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.BlurAnnotator">BlurAnnotator</a></h2>
</div>
:::supervision.annotators.core.BlurAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.PixelateAnnotator">PixelateAnnotator</a></h2>
</div>
:::supervision.annotators.core.PixelateAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.TraceAnnotator">TraceAnnotator</a></h2>
</div>
:::supervision.annotators.core.TraceAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.CropAnnotator">CropAnnotator</a></h2>
</div>
:::supervision.annotators.core.CropAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.BackgroundOverlayAnnotator">BackgroundOverlayAnnotator</a></h2>
</div>
:::supervision.annotators.core.BackgroundOverlayAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.ComparisonAnnotator">ComparisonAnnotator</a></h2>
</div>
:::supervision.annotators.core.ComparisonAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.ColorLookup">ColorLookup</a></h2>
</div>
:::supervision.annotators.utils.ColorLookup
+7
View File
@@ -0,0 +1,7 @@
---
comments: true
---
# CompactMask
:::supervision.detection.compact_mask.CompactMask
+8
View File
@@ -0,0 +1,8 @@
---
comments: true
description: API reference for supervision's Detections class — the core data structure for bounding boxes, masks, confidence scores, and tracker IDs.
---
# Detections
:::supervision.detection.core.Detections
+25
View File
@@ -0,0 +1,25 @@
---
comments: true
---
# Legacy Metrics
Starting with `0.23.0`, a new metrics module is being introduced to supervision. Metrics here are part of the legacy evaluation API and will be deprecated in the future.
Install the metrics extra before using this page's APIs:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.detection.ConfusionMatrix">ConfusionMatrix</a></h2>
</div>
:::supervision.metrics.detection.ConfusionMatrix
<div class="md-typeset">
<h2><a href="#supervision.metrics.detection.MeanAveragePrecision">MeanAveragePrecision</a></h2>
</div>
:::supervision.metrics.detection.MeanAveragePrecision
+54
View File
@@ -0,0 +1,54 @@
---
comments: true
---
# InferenceSlicer
## GeoTIFF Datasets
Install the optional GeoTIFF dependencies before running this example:
```bash
pip install "supervision[geotiff]"
wget -O RGB.byte.tif https://raw.githubusercontent.com/rasterio/rasterio/main/tests/data/RGB.byte.tif
```
`InferenceSlicer` can read an open `rasterio` dataset window-by-window. This keeps large GeoTIFFs out of memory while passing each tile to the callback as an `(H, W, C)` NumPy array.
```python
import numpy as np
import rasterio
import supervision as sv
def callback(tile: np.ndarray) -> sv.Detections:
h, w = tile.shape[:2]
return sv.Detections(
xyxy=np.array([[w * 0.25, h * 0.25, w * 0.75, h * 0.75]], dtype=float),
confidence=np.array([0.9]),
class_id=np.array([0]),
)
slicer = sv.InferenceSlicer(
callback=callback,
slice_wh=(256, 256),
overlap_wh=(64, 64),
overlap_filter=sv.OverlapFilter.NONE,
)
with rasterio.open("RGB.byte.tif") as dataset:
detections = slicer(dataset)
print(len(detections))
```
GeoTIFF inputs must use a projected coordinate reference system. Reproject geographic rasters before passing them to `InferenceSlicer`.
<div class="md-typeset">
<h2><a href="#supervision.detection.tools.inference_slicer.WindowedRasterDataset">WindowedRasterDataset</a></h2>
</div>
:::supervision.detection.tools.inference_slicer.WindowedRasterDataset
:::supervision.detection.tools.inference_slicer.InferenceSlicer
+21
View File
@@ -0,0 +1,21 @@
---
comments: true
---
<div class="md-typeset">
<h2>LineZone</h2>
</div>
:::supervision.detection.line_zone.LineZone
<div class="md-typeset">
<h2>LineZoneAnnotator</h2>
</div>
:::supervision.detection.line_zone.LineZoneAnnotator
<div class="md-typeset">
<h2>LineZoneAnnotatorMulticlass</h2>
</div>
:::supervision.detection.line_zone.LineZoneAnnotatorMulticlass
+15
View File
@@ -0,0 +1,15 @@
---
comments: true
---
<div class="md-typeset">
<h2>PolygonZone</h2>
</div>
:::supervision.detection.tools.polygon_zone.PolygonZone
<div class="md-typeset">
<h2>PolygonZoneAnnotator</h2>
</div>
:::supervision.detection.tools.polygon_zone.PolygonZoneAnnotator
+17
View File
@@ -0,0 +1,17 @@
---
comments: true
---
# Save Detections
<div class="md-typeset">
<h2>CSV Sink</h2>
</div>
:::supervision.detection.tools.csv_sink.CSVSink
<div class="md-typeset">
<h2>JSON Sink</h2>
</div>
:::supervision.detection.tools.json_sink.JSONSink
+7
View File
@@ -0,0 +1,7 @@
---
comments: true
---
# Detection Smoother
:::supervision.detection.tools.smoother.DetectionsSmoother
+41
View File
@@ -0,0 +1,41 @@
---
comments: true
---
# Boxes Utils
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.boxes.move_boxes">move_boxes</a></h2>
</div>
:::supervision.detection.utils.boxes.move_boxes
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.boxes.scale_boxes">scale_boxes</a></h2>
</div>
:::supervision.detection.utils.boxes.scale_boxes
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.boxes.clip_boxes">clip_boxes</a></h2>
</div>
:::supervision.detection.utils.boxes.clip_boxes
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.boxes.pad_boxes">pad_boxes</a></h2>
</div>
:::supervision.detection.utils.boxes.pad_boxes
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.boxes.denormalize_boxes">denormalize_boxes</a></h2>
</div>
:::supervision.detection.utils.boxes.denormalize_boxes
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.boxes.xyxyxyxy_to_xyxy">xyxyxyxy_to_xyxy</a></h2>
</div>
:::supervision.detection.utils.boxes.xyxyxyxy_to_xyxy
+84
View File
@@ -0,0 +1,84 @@
---
comments: true
status: new
---
# Converters Utils
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.xyxy_to_xywh">xyxy_to_xywh</a></h2>
</div>
:::supervision.detection.utils.converters.xyxy_to_xywh
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.xywh_to_xyxy">xywh_to_xyxy</a></h2>
</div>
:::supervision.detection.utils.converters.xywh_to_xyxy
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.xyxy_to_xcycarh">xyxy_to_xcycarh</a></h2>
</div>
:::supervision.detection.utils.converters.xyxy_to_xcycarh
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.xcycwh_to_xyxy">xcycwh_to_xyxy</a></h2>
</div>
:::supervision.detection.utils.converters.xcycwh_to_xyxy
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.xyxy_to_polygons">xyxy_to_polygons</a></h2>
</div>
:::supervision.detection.utils.converters.xyxy_to_polygons
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.mask_to_xyxy">mask_to_xyxy</a></h2>
</div>
:::supervision.detection.utils.converters.mask_to_xyxy
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.mask_to_polygons">mask_to_polygons</a></h2>
</div>
:::supervision.detection.utils.converters.mask_to_polygons
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.polygon_to_mask">polygon_to_mask</a></h2>
</div>
:::supervision.detection.utils.converters.polygon_to_mask
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.polygon_to_xyxy">polygon_to_xyxy</a></h2>
</div>
:::supervision.detection.utils.converters.polygon_to_xyxy
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.xyxy_to_mask">xyxy_to_mask</a></h2>
</div>
:::supervision.detection.utils.converters.xyxy_to_mask
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.rle_to_mask">rle_to_mask</a></h2>
</div>
:::supervision.detection.utils.converters.rle_to_mask
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.mask_to_rle">mask_to_rle</a></h2>
</div>
:::supervision.detection.utils.converters.mask_to_rle
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.converters.is_compressed_rle">is_compressed_rle</a></h2>
</div>
:::supervision.detection.utils.converters.is_compressed_rle
+83
View File
@@ -0,0 +1,83 @@
---
comments: true
---
# IoU and NMS Utils
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.OverlapFilter">OverlapFilter</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.OverlapFilter
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.OverlapMetric">OverlapMetric</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.OverlapMetric
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.utils.box_iou">box_iou</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.box_iou
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.box_iou_batch">box_iou_batch</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.box_iou_batch
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.box_iou_batch_with_jaccard">box_iou_batch_with_jaccard</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.box_iou_batch_with_jaccard
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.mask_iou_batch">mask_iou_batch</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.mask_iou_batch
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.oriented_box_iou_batch">oriented_box_iou_batch</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.oriented_box_iou_batch
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.box_non_max_suppression">box_non_max_suppression</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.box_non_max_suppression
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.mask_non_max_suppression">mask_non_max_suppression</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.mask_non_max_suppression
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.box_non_max_merge">box_non_max_merge</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.box_non_max_merge
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.mask_non_max_merge">mask_non_max_merge</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.mask_non_max_merge
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.oriented_box_non_max_suppression">oriented_box_non_max_suppression</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.oriented_box_non_max_suppression
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.iou_and_nms.oriented_box_non_max_merge">oriented_box_non_max_merge</a></h2>
</div>
:::supervision.detection.utils.iou_and_nms.oriented_box_non_max_merge
+42
View File
@@ -0,0 +1,42 @@
---
comments: true
status: new
---
# Masks Utils
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.masks.mask_to_roi">mask_to_roi</a></h2>
</div>
:::supervision.detection.utils.masks.mask_to_roi
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.masks.move_masks">move_masks</a></h2>
</div>
:::supervision.detection.utils.masks.move_masks
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.masks.contains_holes">contains_holes</a></h2>
</div>
:::supervision.detection.utils.masks.contains_holes
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.masks.contains_multiple_segments">contains_multiple_segments</a></h2>
</div>
:::supervision.detection.utils.masks.contains_multiple_segments
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.masks.filter_segments_by_distance">filter_segments_by_distance</a></h2>
</div>
:::supervision.detection.utils.masks.filter_segments_by_distance
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.masks.calculate_masks_centroids">calculate_masks_centroids</a></h2>
</div>
:::supervision.detection.utils.masks.calculate_masks_centroids
+17
View File
@@ -0,0 +1,17 @@
---
comments: true
---
# Polygons Utils
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.polygons.filter_polygons_by_area">filter_polygons_by_area</a></h2>
</div>
:::supervision.detection.utils.polygons.filter_polygons_by_area
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.polygons.approximate_polygon">approximate_polygon</a></h2>
</div>
:::supervision.detection.utils.polygons.approximate_polygon
+36
View File
@@ -0,0 +1,36 @@
---
comments: true
status: new
---
# VLM Utils
<div class="md-typeset">
<h2><a href="#supervision.detection.vlm.VLM">VLM</a></h2>
</div>
:::supervision.detection.vlm.VLM
<div class="md-typeset">
<h2><a href="#supervision.detection.vlm.LMM">LMM</a></h2>
</div>
:::supervision.detection.vlm.LMM
<div class="md-typeset">
<h2><a href="#supervision.detection.vlm.validate_vlm_parameters">validate_vlm_parameters</a></h2>
</div>
:::supervision.detection.vlm.validate_vlm_parameters
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.vlms.edit_distance">edit_distance</a></h2>
</div>
:::supervision.detection.utils.vlms.edit_distance
<div class="md-typeset">
<h2><a href="#supervision.detection.utils.vlms.fuzzy_match_index">fuzzy_match_index</a></h2>
</div>
:::supervision.detection.utils.vlms.fuzzy_match_index
+58
View File
@@ -0,0 +1,58 @@
---
comments: true
description: Frequently asked questions about installing Supervision, supported computer vision models, datasets, tracking, metrics, and licensing.
---
# Frequently Asked Questions
## What is Supervision?
Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a unified `Detections` class with converters for supported object detection, segmentation, and VLM outputs.
## How do I install Supervision?
Install the base package with:
```bash
pip install supervision
```
Use the `metrics` extra when you need optional metric dependencies:
```bash
pip install "supervision[metrics]"
```
Sample asset utilities are part of the base package under `supervision.assets`.
## Which object detection models work with Supervision?
Supervision is model agnostic. `sv.Detections` includes converters for Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers outputs, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers including Florence-2, PaliGemma, Qwen VL, Gemini, DeepSeek VL 2, and Moondream. Keypoint outputs have separate `sv.KeyPoints` converters, including MediaPipe.
## What can I do with Supervision?
You can annotate images and video, filter detections, track objects, count objects in zones or across lines, load and convert datasets, evaluate models with detection metrics, and export predictions for downstream analysis.
## How do I track objects across video frames?
Assign persistent tracker IDs before visualization. The built-in `sv.ByteTrack` wrapper accepts `Detections` through `update_with_detections()`, but it is deprecated in favor of `ByteTrackTracker` from the external `trackers` package. After tracking, combine the output with annotators such as `sv.TraceAnnotator`, `sv.BoxAnnotator`, and `sv.LabelAnnotator`.
## What dataset formats does Supervision support?
For detection datasets, Supervision supports YOLO, COCO JSON, Pascal VOC, CreateML, and LabelMe. Use `DetectionDataset.from_yolo()`, `DetectionDataset.from_coco()`, `DetectionDataset.from_pascal_voc()`, `DetectionDataset.from_createml()`, or `DetectionDataset.from_labelme()` to load datasets, and the matching `as_*` methods to export them.
## How do I count objects in a zone?
Use `sv.PolygonZone` for arbitrary polygon regions and `sv.LineZone` for line-crossing counts. Line crossing requires `detections.tracker_id`, so run a tracker before calling the line zone trigger.
## How do I benchmark a model?
Install `supervision[metrics]`, then use `supervision.metrics.mean_average_precision.MeanAveragePrecision` for mAP and `sv.ConfusionMatrix` for confusion matrices. Accumulate predictions and ground-truth `Detections`, then call `compute()` to calculate metrics.
## Is Supervision free to use?
Yes. Supervision is free and open source under the MIT license.
## Where is the source code?
The source code is available at [github.com/roboflow/supervision](https://github.com/roboflow/supervision).
+478
View File
@@ -0,0 +1,478 @@
---
comments: true
description: Benchmark object detection models with supervision — compute mAP, confusion matrix, and per-class metrics to compare model performance.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
date_modified: 2026-04-22
---
![Corgi Example](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/corgi-sorted-2.png)
# Benchmark a Model
Have you ever trained multiple detection models and wondered which one performs best on your specific use case? Or maybe you've downloaded a pre-trained model and want to verify its performance on your dataset? Model benchmarking is essential for making informed decisions about which model to deploy in production.
This guide will show an easy way to benchmark your results using `supervision`. It will go over:
1. [Loading a dataset](#loading-a-dataset)
2. [Loading a model](#loading-a-model)
3. [Benchmarking Basics](#benchmarking-basics)
4. [Running a Model](#running-a-model)
5. [Remapping Classes](#remapping-classes)
6. [Visual Benchmarking](#visual-benchmarking)
7. [Benchmarking Metrics](#benchmarking-metrics)
8. [Mean Average Precision (mAP)](#mean-average-precision-map)
9. [F1 Score](#f1-score)
10. [Bonus: Model Leaderboard](#model-leaderboard)
This guide will use an instance segmentation model, but it applies to object detection, instance segmentation, and oriented bounding box models (OBB) too.
A condensed version of this guide is available as a [Colab Notebook](https://colab.research.google.com/drive/1HoOY9pZoVwGiRMmLHtir0qT6Uj45w6Ps?usp=sharing).
## Loading a Dataset
Suppose you start with a dataset. Perhaps you found it on [Universe](https://universe.roboflow.com/); perhaps you [labeled your own](https://roboflow.com/how-to-label/yolo11). In either case, this guide assumes you know of a labelled dataset at hand.
We'll use the following libraries:
- `roboflow` to manage the dataset and deploy models
- `inference` to run the models
- `supervision` to evaluate the model results
```bash
pip install roboflow inference "supervision[metrics]"
```
Here's how you can download a dataset:
```python
from roboflow import Roboflow
rf = Roboflow(api_key="<YOUR_API_KEY>")
project = rf.workspace("<WORKSPACE_NAME>").project("<PROJECT_NAME>")
dataset = project.version("<DATASET_VERSION_NUMBER>").download("<FORMAT>")
```
If your dataset is from Universe, go to `Dataset` > `Download Dataset` > select the format (e.g. `YOLOv11`) > `Show download code`.
If labeling your own data, go to the [dashboard](https://app.roboflow.com/) and check this [guide](https://docs.roboflow.com/api-reference/workspace-and-project-ids) to find your workspace and project IDs.
In this guide, we shall use a small [Corgi v2](https://universe.roboflow.com/model-examples/segmented-animals-basic) dataset. It is well-labeled and comes with a test set.
```python
from roboflow import Roboflow
rf = Roboflow(api_key="<YOUR_API_KEY>")
project = rf.workspace("fbamse1-gm2os").project("corgi-v2")
dataset = project.version(4).download("yolov11")
```
This will create a folder called `Corgi-v2-4` with the dataset in the current working directory, with `train`, `test`, and `valid` folders and a `data.yaml` file.
## Loading a Model
Let's load a model.
Select and instantiate the detection or segmentation model you want to benchmark. Supervision works with Roboflow Inference for both local and cloud-deployed models, as well as Ultralytics YOLO checkpoints. Choose the tab below that matches your preferred framework, then pass images to the loaded model during the evaluation loop.
=== "Inference, Local"
Roboflow supports a range of state-of-the-art [pre-trained models](https://inference.roboflow.com/quickstart/aliases/) for object detection, instance segmentation, and pose tracking. You don't even need an API key!
Let's load such a model with inference [`inference`](https://inference.roboflow.com/).
```python
from inference import get_model
model = get_model(model_id="yolov11s-seg-640")
```
=== "Inference, Deployed"
You can train and deploy a model without leaving the Roboflow platform. See this [guide](https://docs.roboflow.com/train/train/train-from-scratch) for more details.
To load a model, you can use inference:
```python
from inference import get_model
model_id = "<PROJECT_NAME>/<MODEL_VERSION>"
model = get_model(model_id=model_id)
```
=== "Ultralytics"
Similarly to Inference, Ultralytics allows you to run a variety of models.
```bash
pip install "ultralytics<=8.3.40"
```
```python
from ultralytics import YOLO
model = YOLO("yolo11s-seg.pt")
```
## Benchmarking Basics
Evaluating your model requires careful selection of the dataset. Which images should you use?Let's go over the different scenarios.
- **Unrelated Dataset**: If you have a dataset that was not used to train the model, this is the best choice.
- **Training Set**: This is the set of images used to train the model. This is fine if the model was not trained on this dataset. Otherwise, **never** use it for benchmarking - the results will seem unrealistically good.
- **Validation Set**: This is the set of images used to validate the model during training. Every Nth training epoch, the model is evaluated on the validation set. Often the training is stopped once the validation loss stops improving. Therefore, even while the images aren't used to train the model, it still indirectly influences the training outcome.
- **Test Set**: This is the set of images kept aside for model testing. It is exactly the set you should use for benchmarking. If the dataset was split correctly, none of these images would be shown to the model during training.
Therefore, an unrelated dataset or the `test` set is the best choice for benchmarking. Several other problems may arise:
- **Extra Classes**: An unrelated dataset may contain additional classes which you may need to [filter out](https://supervision.roboflow.com/how_to/filter_detections/#by-set-of-classes) before computing metrics.
- **Class Mismatch**: In an unrelated dataset, the class names or IDs may be different to what your model produces, you'll need to remap them, which is [shown in this guide](#running-a-model).
- **Data Contamination**: The `test` set may not be split correctly, with images from the test set also present in `training` or `validation` set and used during training. In this case, the results will be overly optimistic. This also applies when **very similar** images are used for training and testing - e.g. those taken in the same environment, same lighting conditions, similar angle, etc.
- **Missing Test Set**: Some datasets do not come with a test set. In this case, you should collect and [label](https://roboflow.com/annotate) your own data. Alternatively, a validation set could be used, but the results could be overly optimistic. Make sure to test in the real world as soon as possible.
## Running a Model
At this stage, you should have:
- A dataset of labeled images to evaluate the model.
- A model prepared for benchmarking.
With these ready, we can now run the model and obtain predictions. We'll use `supervision` to create a dataset iterator, and then run the model on each image.
=== "Inference"
```python
import supervision as sv
test_set = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/test/images",
annotations_directory_path=f"{dataset.location}/test/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
image_paths = []
predictions_list = []
targets_list = []
for image_path, image, label in test_set:
result = model.infer(image)[0]
predictions = sv.Detections.from_inference(result)
image_paths.append(image_path)
predictions_list.append(predictions)
targets_list.append(label)
```
=== "Ultralytics"
```python
import supervision as sv
test_set = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/test/images",
annotations_directory_path=f"{dataset.location}/test/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
image_paths = []
predictions_list = []
targets_list = []
for image_path, image, label in test_set:
result = model(image)[0]
predictions = sv.Detections.from_ultralytics(result)
image_paths.append(image_path)
predictions_list.append(predictions)
targets_list.append(label)
```
## Remapping classes
Did you notice an issue in the above logic? Since we're using an unrelated dataset, the class names and IDs may be different from what the model was trained on.
We need to remap them to match the dataset classes. Here's how to do it:
```python
def remap_classes(
detections: sv.Detections,
class_ids_from_to: dict[int, int],
class_names_from_to: dict[str, str],
) -> None:
new_class_ids = [
class_ids_from_to.get(class_id, class_id) for class_id in detections.class_id
]
detections.class_id = np.array(new_class_ids)
new_class_names = [
class_names_from_to.get(name, name) for name in detections["class_name"]
]
predictions["class_name"] = np.array(new_class_names)
```
Let's also remove the predictions that are not in the dataset classes.
=== "Inference"
Dataset class names and IDs can be found in the `data.yaml` file, or by printing `dataset.classes`.
```python
import supervision as sv
test_set = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/test/images",
annotations_directory_path=f"{dataset.location}/test/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
image_paths = []
predictions_list = []
targets_list = []
for image_path, image, label in test_set:
result = model.infer(image)[0]
predictions = sv.Detections.from_inference(result)
remap_classes(
detections=predictions,
class_ids_from_to={16: 0},
class_names_from_to={"dog": "Corgi"},
)
predictions = predictions[np.isin(predictions["class_name"], test_set.classes),]
image_paths.append(image_path)
predictions_list.append(predictions)
targets_list.append(label)
```
=== "Ultralytics"
Dataset class names and IDs can be found in the `data.yaml` file, or by printing `dataset.classes`.
Each model will have a different class mapping, so make sure to check the model's documentation. In this case, the model was trained on the COCO dataset, with a class configuration found [here](https://github.com/ultralytics/ultralytics/blob/main/ultralytics/cfg/datasets/coco8.yaml).
```python
import supervision as sv
test_set = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/test/images",
annotations_directory_path=f"{dataset.location}/test/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
image_paths = []
predictions_list = []
targets_list = []
for image_path, image, label in test_set:
result = model(image)[0]
predictions = sv.Detections.from_ultralytics(result)
remap_classes(
detections=predictions,
class_ids_from_to={16: 0},
class_names_from_to={"dog": "Corgi"},
)
predictions = predictions[np.isin(predictions["class_name"], test_set.classes),]
image_paths.append(image_path)
predictions_list.append(predictions)
targets_list.append(label)
```
## Visualizing Predictions
The first step in evaluating your models performance is to visualize its predictions. This gives an intuitive sense of how well your model is detecting objects and where it might be failing.
```python
import supervision as sv
N = 9
GRID_SIZE = (3, 3)
target_annotator = sv.PolygonAnnotator(color=sv.Color.from_hex("#8315f9"), thickness=8)
prediction_annotator = sv.PolygonAnnotator(
color=sv.Color.from_hex("#00cfc6"), thickness=6
)
annotated_images = []
for image_path, predictions, targets in zip(
image_paths[:N], predictions_list[:N], targets_list[:N]
):
annotated_image = cv2.imread(image_path)
annotated_image = target_annotator.annotate(
scene=annotated_image, detections=targets
)
annotated_image = prediction_annotator.annotate(
scene=annotated_image, detections=prediction
)
annotated_images.append(annotated_image)
sv.plot_images_grid(images=annotated_images, grid_size=GRID_SIZE)
```
Here, predictions in purple are targets (ground truth), and predictions in teal are model predictions.
![Basic Model Comparison](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/basic-model-comparison-corgi.png)
!!! tip
Use `sv.BoxAnnotator` for object detection and `sv.OrientedBoxAnnotator` for OBB.
See [annotator documentation](https://supervision.roboflow.com/latest/detection/annotators/) for even more options.
## Visual Benchmarking
To inspect where a model succeeds and fails, pass `save_directory_path` to `sv.ConfusionMatrix.benchmark(...)`. For every dataset image it writes a 2x2 result grid — `Ground Truth`, `True Positives`, `False Positives`, and `False Negatives` panels — directly into that directory, reusing the original image filenames. This makes it easy to skim through per-image outcomes alongside the aggregate confusion matrix.
```python
import supervision as sv
confusion_matrix = sv.ConfusionMatrix.benchmark(
dataset=test_set,
callback=callback,
save_directory_path="./results",
)
```
## Benchmarking Metrics
With multiple models, fine details matter. Visual inspection may not be enough. `supervision` provides a collection of metrics that help obtain precise numerical results of model performance.
### Mean Average Precision (mAP)
We'll start with [MeanAveragePrecision (mAP)](https://supervision.roboflow.com/latest/metrics/mean_average_precision/#supervision.metrics.mean_average_precision.MeanAveragePrecision), which is the most commonly used metric for object detection. It measures the average precision across all classes and IoU thresholds.
For a thorough explanation, check out our [blog](https://blog.roboflow.com/mean-average-precision/) and [Youtube video](https://www.youtube.com/watch?v=oqXDdxF_Wuw).
Here, the most popular value is `mAP 50:95`. It represents the average precision across all classes and IoU thresholds (`0.5` to `0.95`), whereas other values such as `mAP 50` or `mAP 75` only consider a single IoU threshold (`0.5` and `0.75` respectively).
Let's compute the mAP:
```python
from supervision.metrics import MeanAveragePrecision, MetricTarget
map_metric = MeanAveragePrecision(metric_target=MetricTarget.MASKS)
map_result = map_metric.update(predictions_list, targets_list).compute()
```
Try printing the result to see it at a glance:
```python
print(map_result)
```
```
MeanAveragePrecisionResult:
Metric target: MetricTarget.MASKS
Class agnostic: False
mAP @ 50:95: 0.2409
mAP @ 50: 0.3591
mAP @ 75: 0.2915
mAP scores: [0.35909 0.3468 0.34556 ...]
IoU thresh: [0.5 0.55 0.6 ...]
AP per class:
0: [0.35909 0.3468 0.34556 ...]
...
Small objects: ...
Medium objects: ...
Large objects: ...
```
You can also plot the results:
```python
map_result.plot()
```
![mAP Plot](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/mAP-plot-corgi.png)
The metric also breaks down the results by detected object area. Small, medium and large are simply those with area less than 32², between 32² and 96², and greater than 96² pixels respectively.
### F1 Score
The [F1 Score](https://supervision.roboflow.com/latest/metrics/f1_score/) is another useful metric, especially when dealing with an imbalance between false positives and false negatives. Its the harmonic mean of **precision** (how many predictions are correct) and **recall** (how many actual instances were detected).
Here's how you can compute the F1 score:
```python
from supervision.metrics import F1Score, MetricTarget
f1_metric = F1Score(metric_target=MetricTarget.MASKS)
f1_result = f1_metric.update(predictions_list, targets_list).compute()
```
As with mAP, you can also print the result:
```python
print(f1_result)
```
```
F1ScoreResult:
Metric target: MetricTarget.MASKS
Averaging method: AveragingMethod.WEIGHTED
F1 @ 50: 0.5341
F1 @ 75: 0.4636
F1 @ thresh: [0.53406 0.5278 0.52153 ...]
IoU thresh: [0.5 0.55 0.6 ...]
F1 per class:
0: [0.53406 0.5278 0.52153 ...]
...
Small objects: ...
Medium objects: ...
Large objects: ...
```
Similarly, you can plot the results:
```python
f1_result.plot()
```
![F1 Plot](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/f1-score-corgi.png)
As with mAP, the metric also breaks down the results by detected object area. Small, medium and large are simply those with area less than 32², between 32² and 96², and greater than 96² pixels respectively.
## Model Leaderboard
Here to compare the basic models? We've got you covered. Check out our [Model Leaderboard](https://leaderboard.roboflow.com/) to see how different models perform and to get a sense of the state-of-the-art results. It's a great place to understand what the leading models can achieve and to compare your own results.
Even better, the repository is open source! You can see how the models were benchmarked, run the evaluation yourself, and even add your own models to the leaderboard. Check it out on [GitHub](https://github.com/roboflow/model-leaderboard)!
![Model Leaderboard Example](https://media.roboflow.com/model-leaderboard/model-leaderboard-example.png)
## Conclusion
In this guide, you've learned how to set up your environment, train or use pre-trained models, visualize predictions, and evaluate model performance with metrics like [mAP](https://supervision.roboflow.com/latest/metrics/mean_average_precision/), [F1 score](https://supervision.roboflow.com/latest/metrics/f1_score/), and got to know our Model Leaderboard.
A condensed version of this guide is also available as a [Colab Notebook](https://colab.research.google.com/drive/1HoOY9pZoVwGiRMmLHtir0qT6Uj45w6Ps?usp=sharing).
For more details, be sure to check out our [documentation](https://supervision.roboflow.com/latest/) and join our community discussions. If you find any issues, please let us know on [GitHub](https://github.com/roboflow/supervision/issues).
Best of luck with your benchmarking!
## Frequently Asked Questions
### How do I benchmark a model with supervision?
Use `supervision.metrics.mean_average_precision.MeanAveragePrecision` — accumulate prediction and ground-truth `Detections` with `update(...)` and then call `compute()`. For confusion matrices, use `sv.ConfusionMatrix.from_detections(predictions=predictions, targets=targets, classes=classes)`.
### What IoU thresholds does MeanAveragePrecision use?
It computes mAP over IoU thresholds from 0.50 to 0.95 in steps of 0.05 (mAP@50:95), plus mAP@50 and mAP@75 individually.
### Can I benchmark segmentation models?
Yes, if you want to evaluate their bounding boxes. Convert model outputs to `Detections` and pass them to `MeanAveragePrecision.update(...)`; the current mAP path prepares COCO-style bounding boxes from `detections.xyxy`.
### What is a ConfusionMatrix and how do I use it?
`sv.ConfusionMatrix` visualizes true positives, false positives, and false negatives per class. Create one with `sv.ConfusionMatrix.from_detections(predictions=predictions, targets=targets, classes=classes, conf_threshold=0.5, iou_threshold=0.5)`, then call `confusion_matrix.plot()` to render a heatmap. If you want per-image validation visualizations saved to disk, pass `save_directory_path="./results"` to `sv.ConfusionMatrix.benchmark(...)`; it will write 2x2 result grids directly into that directory using the original image filenames, with `Ground Truth`, `True Positives`, `False Positives`, and `False Negatives` panels.
## Author
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
+150
View File
@@ -0,0 +1,150 @@
---
comments: true
description: Count objects entering a polygon zone in images and video using supervision's PolygonZone — measure throughput and density in any region.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
date_modified: 2026-04-22
---
With supervision, you can count the number of objects in a zone in an image or video. In this guide, we will show how to count the number of cars in a traffic video.
[View the notebook that accompanies this tutorial](https://github.com/roboflow/notebooks/blob/main/notebooks/how-to-use-polygonzone-annotate-and-supervision.ipynb).
To make it easier for you to follow our tutorial download the video we will use as an example. You can do this using the `supervision.assets` module:
```python
from supervision.assets import download_assets, VideoAssets
download_assets(VideoAssets.VEHICLES_2)
```
## Initialize a Model and Load Video
First, we need to initialize a model. Let's use a YOLOv8 model with the default COCO checkpoint. We also need to load a video on which to run inference.
Create a YOLO model instance and download the source video. The model will process each frame during inference. A shared color palette ensures consistent zone coloring throughout the output video.
```python
import numpy as np
import supervision as sv
import cv2
from ultralytics import YOLO
from supervision.assets import VideoAssets, download_assets
model = YOLO("yolov8s.pt")
VIDEO = download_assets(VideoAssets.VEHICLES_2)
colors = sv.ColorPalette.DEFAULT
```
## Calculate Coordinates
To count objects in a zone, you need to know the coordinates where you want to draw the zone.
You can calculate coordinates using the [PolygonZone web utility](https://roboflow.github.io/polygonzone/).
To use the PolygonZone website, you will need to upload an image or frame from a video. You can retrieve a frame using this code:
```python
generator = sv.get_video_frames_generator(VIDEO)
iterator = iter(generator)
frame = next(iterator)
cv2.imwrite("first_frame.png", frame)
```
PolygonZone will give you NumPy arrays that you can use with supervision to count objects in zones.
<video width="100%" loop muted autoplay>
<source src="https://media.roboflow.com/polygonzone.mp4" type="video/mp4">
</video>
Save the coordinates in an array:
```python
polygons = [
np.array([[718, 595], [927, 592], [851, 1062], [42, 1059]]),
np.array([[987, 595], [1199, 595], [1893, 1056], [1015, 1062]]),
]
```
## Define Zones
With the coordinates of the zones to draw ready, we can set up our zones:
Instantiate a `PolygonZone` for each polygon array, pairing it with a `PolygonZoneAnnotator` for visual overlay and a `BoxAnnotator` for drawing detection boxes. Each zone will later trigger on incoming detections to determine which objects fall inside its boundaries, enabling per-zone counting in the inference callback.
```python
zones = [sv.PolygonZone(polygon=polygon) for polygon in polygons]
zone_annotators = [
sv.PolygonZoneAnnotator(
zone=zone,
color=colors.by_idx(index),
thickness=4,
text_thickness=8,
text_scale=4,
)
for index, zone in enumerate(zones)
]
box_annotators = [
sv.BoxAnnotator(
color=colors.by_idx(index),
thickness=4,
)
for index in range(len(polygons))
]
```
## Run Inference
We can run inference on a video using the [sv.process_video](https://supervision.roboflow.com/utils/video/#process_video) function. This function accepts a callback that runs inference on each frame and compiles the results into a video.
Below, we can call our YOLOv8 model, annotate predictions and zones, then save the results to a file called `result.mp4`.
```python
def process_frame(frame: np.ndarray, i) -> np.ndarray:
results = model(frame, imgsz=1280, verbose=False)[0]
detections = sv.Detections.from_ultralytics(results)
for zone, zone_annotator, box_annotator in zip(
zones, zone_annotators, box_annotators
):
mask = zone.trigger(detections=detections)
detections_filtered = detections[mask]
frame = box_annotator.annotate(scene=frame, detections=detections_filtered)
frame = zone_annotator.annotate(scene=frame)
return frame
sv.process_video(source_path=VIDEO, target_path="result.mp4", callback=process_frame)
```
Here is an example of inference run on the video:
<video width="100%" loop muted autoplay>
<source src="https://blog.roboflow.com/content/media/2023/03/trim-counting.mp4" type="video/mp4">
</video>
## Frequently Asked Questions
### How do I count objects in a zone with supervision?
Create `sv.PolygonZone` with a polygon defining your region. Call `zone.trigger(detections)` on each frame — it returns a mask of detections inside the zone.
### Can I count objects crossing a line instead of entering a zone?
Yes. Use `sv.LineZone` — define a start and end point. `zone.trigger(detections)` returns a tuple of two boolean arrays, `(crossed_in, crossed_out)`, indicating which detections crossed the line in each direction. `LineZone` requires `detections.tracker_id`; run a tracker first so the same object can be matched across frames.
### Can I combine zone counting with tracking?
Yes. You can pass tracker IDs from `sv.ByteTrack` alongside your detections, but `sv.PolygonZone` still evaluates the zone on each frame and reports which objects are currently inside it. If you want to count each object only once when it first enters the zone, maintain a set of seen `tracker_id` values after filtering detections with `zone.trigger(detections)`, or use a dedicated entry/crossing counting tool such as `sv.LineZone` when it better matches your use case.
## Author
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
+460
View File
@@ -0,0 +1,460 @@
---
comments: true
description: Learn to load model predictions, create Detections objects, and annotate images with bounding boxes, labels, and masks using supervision.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
- name: Borda
role: Open Source Engineer, Roboflow
github: https://github.com/borda
date_modified: 2026-04-22
---
# Detect and Annotate
!!! tip "Sample Image"
Don't have an image? Download the one used in this tutorial:
```bash
wget https://media.roboflow.com/notebooks/examples/dog.jpeg
```
```
Then replace `<SOURCE_IMAGE_PATH>` with `"dog.jpeg"`.
```
Supervision provides a seamless process for annotating predictions generated by various object detection and segmentation models. This guide shows how to perform inference with the [Inference](https://github.com/roboflow/inference), [Ultralytics](https://github.com/ultralytics/ultralytics) or [Transformers](https://github.com/huggingface/transformers) packages. Following this, you'll learn how to import these predictions into Supervision and use them to annotate source image.
![basic-annotation](https://media.roboflow.com/supervision_detect_and_annotate_example_1.png)
## Run Detection
First, you'll need to obtain predictions from your object detection or segmentation model.
To run inference, initialize your chosen model and pass the source image to its predict or infer method. Supervision supports Roboflow Inference, Ultralytics YOLO, and Hugging Face Transformers -- select the tab matching your framework. The result is a framework-specific object you will convert to a `Detections` instance in the next step.
=== "Inference"
```python
import cv2
from inference import get_model
model = get_model(model_id="yolov8n-640")
image = cv2.imread("dog.jpeg")
results = model.infer(image)[0]
```
=== "Ultralytics"
```python
import cv2
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
image = cv2.imread("dog.jpeg")
results = model(image)[0]
```
=== "Transformers"
```python
import torch
from PIL import Image
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = Image.open("dog.jpeg")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size
)[0]
```
## Load Predictions into Supervision
Now that we have predictions from a model, we can load them into Supervision.
Each supported framework has a dedicated class method on `sv.Detections` that converts raw model output into a unified Supervision object. Call `from_inference`, `from_ultralytics`, or `from_transformers` depending on the package you used for inference. This normalization step ensures all downstream annotators and filters work identically regardless of the source model.
=== "Inference"
We can do so using the [`sv.Detections.from_inference`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_inference) method, which accepts model results from both detection and segmentation models.
```{ .py hl_lines="2 8" }
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)
```
=== "Ultralytics"
We can do so using the [`sv.Detections.from_ultralytics`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_ultralytics) method, which accepts model results from both detection and segmentation models.
```{ .py hl_lines="2 8" }
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)
```
=== "Transformers"
We can do so using the [`sv.Detections.from_transformers`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_transformers) method, which accepts model results from both detection and segmentation models.
```{ .py hl_lines="2 19-21" }
import torch
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = Image.open("dog.jpeg")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers(
transformers_results=results,
id2label=model.config.id2label)
```
You can load predictions from other computer vision frameworks and libraries using:
- [`from_deepsparse`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_deepsparse) ([Deepsparse](https://github.com/neuralmagic/deepsparse))
- [`from_detectron2`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_detectron2) ([Detectron2](https://github.com/facebookresearch/detectron2))
- [`from_mmdetection`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_mmdetection) ([MMDetection](https://github.com/open-mmlab/mmdetection))
- [`from_sam`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_sam) ([Segment Anything Model](https://github.com/facebookresearch/segment-anything))
- [`from_yolo_nas`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections.from_yolo_nas) ([YOLO-NAS](https://github.com/Deci-AI/super-gradients/blob/master/YOLONAS.md))
## Annotate Image with Detections
Finally, we can annotate the image with the predictions. Since we are working with an object detection model, we will use the [`sv.BoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoxAnnotator) and [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.LabelAnnotator) classes.
To draw bounding boxes and class labels on your image, create a `BoxAnnotator` and a `LabelAnnotator`, then call their `annotate` methods in sequence. Each annotator returns the modified image, so you can chain multiple annotators together. The result is a single NumPy array with all visual overlays rendered and ready for display or saving.
=== "Inference"
```{ .py hl_lines="10-16" }
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_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
=== "Ultralytics"
```{ .py hl_lines="10-16" }
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_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
=== "Transformers"
```{ .py hl_lines="23-30" }
import torch
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = Image.open("dog.jpeg")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers(
transformers_results=results,
id2label=model.config.id2label)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
![basic-annotation](https://media.roboflow.com/supervision_detect_and_annotate_example_1.png)
## Display Custom Labels
By default, [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.LabelAnnotator) will label each detection with its `class_name` (if possible) or `class_id`. You can override this behavior by passing a list of custom `labels` to the `annotate` method.
=== "Inference"
```{ .py hl_lines="13-17 22" }
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()
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence
in zip(detections['class_name'], detections.confidence)
]
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections, labels=labels)
```
=== "Ultralytics"
```{ .py hl_lines="13-17 22" }
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()
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence
in zip(detections['class_name'], detections.confidence)
]
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections, labels=labels)
```
=== "Transformers"
```{ .py hl_lines="26-30 35" }
import torch
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = Image.open("dog.jpeg")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers(
transformers_results=results,
id2label=model.config.id2label)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence
in zip(detections['class_name'], detections.confidence)
]
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections, labels=labels)
```
![custom-label-annotation](https://media.roboflow.com/supervision_detect_and_annotate_example_2.png)
## Annotate Image with Segmentations
If you are running the segmentation model [`sv.MaskAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.MaskAnnotator) is a drop-in replacement for [`sv.BoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoxAnnotator) that will allow you to draw masks instead of boxes.
=== "Inference"
```python
import cv2
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8n-seg-640")
image = cv2.imread("dog.jpeg")
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
mask_annotator = sv.MaskAnnotator()
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER_OF_MASS)
annotated_image = mask_annotator.annotate(
scene=image,
detections=detections,
)
annotated_image = label_annotator.annotate(
scene=annotated_image,
detections=detections,
)
sv.plot_image(annotated_image)
```
=== "Ultralytics"
```python
import cv2
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n-seg.pt")
image = cv2.imread("dog.jpeg")
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
mask_annotator = sv.MaskAnnotator()
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER_OF_MASS)
annotated_image = mask_annotator.annotate(
scene=image,
detections=detections,
)
annotated_image = label_annotator.annotate(
scene=annotated_image,
detections=detections,
)
```
=== "Transformers"
```python
import torch
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForSegmentation
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50-panoptic")
model = DetrForSegmentation.from_pretrained("facebook/detr-resnet-50-panoptic")
image = Image.open("dog.jpeg")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_segmentation(
outputs=outputs, target_sizes=target_size
)[0]
detections = sv.Detections.from_transformers(
transformers_results=results, id2label=model.config.id2label
)
mask_annotator = sv.MaskAnnotator()
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER_OF_MASS)
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence in zip(
detections["class_name"],
detections.confidence,
)
]
annotated_image = mask_annotator.annotate(scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections, labels=labels
)
```
![segmentation-annotation](https://media.roboflow.com/supervision_detect_and_annotate_example_3.png)
## Frequently Asked Questions
### How do I detect and annotate objects with supervision?
Pass any model's output to `sv.Detections.from_<model>()` to create a unified `Detections` object. Then pass it to `sv.BoxAnnotator` or `sv.MaskAnnotator` to draw predictions on an image.
### Can I annotate both bounding boxes and masks at the same time?
Yes. Chain annotators: first draw boxes with `BoxAnnotator`, then overlay masks with `MaskAnnotator` on the same scene.
### How do I label detections with class names?
Use `sv.LabelAnnotator` and pass custom text with the `labels` parameter. If a connector provides class names, they are stored in `detections["class_name"]` / `detections.data["class_name"]`; when `labels` is omitted, `LabelAnnotator` uses class names first, then class IDs, then detection indices.
### Can I use supervision with Hugging Face models?
Yes. `sv.Detections.from_transformers()` accepts supported Hugging Face object detection and segmentation outputs. Vision-language model outputs are handled through `sv.Detections.from_vlm(...)`, for example with `sv.VLM.FLORENCE_2` or `sv.VLM.PALIGEMMA`.
## Authors
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
- [Borda](https://github.com/borda) — Open Source Engineer, Roboflow
+347
View File
@@ -0,0 +1,347 @@
---
comments: true
description: Detect small objects in images by applying SAHI inference slicing with supervision's InferenceSlicer — improve recall for tiny targets.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
date_modified: 2026-04-22
---
# Detect Small Objects
This guide shows how to detect small objects with the [Inference](https://github.com/roboflow/inference), [Ultralytics](https://github.com/ultralytics/ultralytics) or [Transformers](https://github.com/huggingface/transformers) packages using [`InferenceSlicer`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/#supervision.detection.tools.inference_slicer.InferenceSlicer).
<video controls>
<source src="https://media.roboflow.com/supervision_detect_small_objects_example.mp4" type="video/mp4">
</video>
## Baseline Detection
Small object detection in high-resolution images presents challenges due to the objects' size relative to the image resolution.
Running a standard detection model on the full image establishes a baseline for comparison. Load your chosen model, pass the image through it, and convert the results into a `Detections` object. This baseline reveals how many small objects the model misses at native resolution, motivating the sliced inference approach shown later.
=== "Inference"
```python
import cv2
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8x-640")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image,
detections=detections,
)
annotated_image = label_annotator.annotate(
scene=annotated_image,
detections=detections,
)
```
=== "Ultralytics"
```python
import cv2
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8x.pt")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image,
detections=detections,
)
annotated_image = label_annotator.annotate(
scene=annotated_image,
detections=detections,
)
```
=== "Transformers"
```python
import torch
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForSegmentation
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForSegmentation.from_pretrained("facebook/detr-resnet-50")
image = Image.open("<SOURCE_IMAGE_PATH>")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image_slice.size
target_size = torch.tensor([[width, height]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size
)[0]
detections = sv.Detections.from_transformers(results)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [model.config.id2label[class_id] for class_id in detections.class_id]
annotated_image = box_annotator.annotate(scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections, labels=labels
)
```
![basic-detection](https://media.roboflow.com/supervision_detect_small_objects_example_1.png)
## Input Resolution
Modifying the input resolution of images before detection can enhance small object identification at the cost of processing speed and increased memory usage. This method is less effective for ultra-high-resolution images (4K and above).
=== "Inference"
```{ .py hl_lines="5" }
import cv2
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8x-1280")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
=== "Ultralytics"
```{ .py hl_lines="7" }
import cv2
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8x.pt")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
results = model(image, imgsz=1280)[0]
detections = sv.Detections.from_ultralytics(results)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
![detection-with-high-input-resolution](https://media.roboflow.com/supervision_detect_small_objects_example_2.png)
## Inference Slicer
[`InferenceSlicer`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/#supervision.detection.tools.inference_slicer.InferenceSlicer) processes high-resolution images by dividing them into smaller segments, detecting objects within each, and aggregating the results.
<video controls>
<source src="https://media.roboflow.com/supervision_detect_small_objects_example_2.mp4" type="video/mp4">
</video>
=== "Inference"
```{ .py hl_lines="9-14" }
import cv2
import numpy as np
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8x-640")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
def callback(image_slice: np.ndarray) -> sv.Detections:
results = model.infer(image_slice)[0]
return sv.Detections.from_inference(results)
slicer = sv.InferenceSlicer(callback = callback)
detections = slicer(image)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
=== "Ultralytics"
```{ .py hl_lines="9-14" }
import cv2
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8x.pt")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
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)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
=== "Transformers"
```{ .py hl_lines="13-28" }
import cv2
import torch
import numpy as np
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
def callback(image_slice: np.ndarray) -> sv.Detections:
image_slice = cv2.cvtColor(image_slice, cv2.COLOR_BGR2RGB)
image_slice = Image.fromarray(image_slice)
inputs = processor(images=image_slice, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = image_slice.size
target_size = torch.tensor([[width, height]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
return sv.Detections.from_transformers(results)
slicer = sv.InferenceSlicer(callback = callback)
detections = slicer(image)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
model.config.id2label[class_id]
for class_id
in detections.class_id
]
annotated_image = box_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections, labels=labels)
```
![detection-with-inference-slicer](https://media.roboflow.com/supervision_detect_small_objects_example_3.png)
## Small Object Segmentation
[`InferenceSlicer`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/#supervision.detection.tools.inference_slicer.InferenceSlicer) can perform segmentation tasks too.
=== "Inference"
```{ .py hl_lines="6 16 19-20" }
import cv2
import numpy as np
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8x-seg-640")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
def callback(image_slice: np.ndarray) -> sv.Detections:
results = model.infer(image_slice)[0]
return sv.Detections.from_inference(results)
slicer = sv.InferenceSlicer(callback = callback)
detections = slicer(image)
mask_annotator = sv.MaskAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = mask_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
=== "Ultralytics"
```{ .py hl_lines="6 16 19-20" }
import cv2
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8x-seg.pt")
image = cv2.imread("<SOURCE_IMAGE_PATH>")
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)
mask_annotator = sv.MaskAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = mask_annotator.annotate(
scene=image, detections=detections)
annotated_image = label_annotator.annotate(
scene=annotated_image, detections=detections)
```
![detection-with-inference-slicer](https://media.roboflow.com/supervision-docs/inference-slicer-segmentation-example.png)
## Frequently Asked Questions
### How do I detect small objects with supervision?
Use `sv.InferenceSlicer` to split a high-resolution image into overlapping tiles, run detection on each tile, and merge results with non-maximum suppression. This dramatically improves recall for tiny targets.
### What overlap should I use between tiles?
`InferenceSlicer` takes overlap in pixels via `overlap_wh`, not as a percentage. The default is `100` pixels in both directions. Increase `overlap_wh` when objects are close to the tile size or often appear on tile boundaries, and decrease it when speed is more important.
### Can I use InferenceSlicer with any detection model?
Yes. Wrap any model or converter path that can produce `sv.Detections` in a callback, pass that callback to `sv.InferenceSlicer(callback=...)`, and then call the slicer with your image.
## Author
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
+335
View File
@@ -0,0 +1,335 @@
---
comments: true
description: Filter and query detection results by class, confidence, or spatial overlap using supervision's Detections API — clean predictions in one line.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
date_modified: 2026-04-22
---
# Filter Detections
The advanced filtering capabilities of the `Detections` class offer users a versatile and efficient way to narrow down and refine object detections. This section outlines various filtering methods, including filtering by specific class or a set of classes, confidence, object area, bounding box area, relative area, box dimensions, and designated zones. Each method is demonstrated with concise code examples to provide users with a clear understanding of how to implement the filters in their applications.
### by specific class
Allows you to select detections that belong only to one selected class.
=== "After"
```python
import supervision as sv
detections = sv.Detections(...)
detections = detections[detections.class_id == 0]
```
<div class="result" markdown>
![by-specific-class](https://media.roboflow.com/open-source/supervision/supervision-detection-by-specific-class.png){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
detections = sv.Detections(...)
detections = detections[detections.class_id == 0]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by set of classes
Allows you to select detections that belong only to selected set of classes.
=== "After"
```python
import numpy as np
import supervision as sv
selected_classes = [0, 2, 3]
detections = sv.Detections(...)
detections = detections[np.isin(detections.class_id, selected_classes)]
```
<div class="result" markdown>
![by-set-of-classes](https://media.roboflow.com/open-source/supervision/supervision-detection-by-set-of-classes.png){ align=center width="800" }
</div>
=== "Before"
```python
import numpy as np
import supervision as sv
class_id = [0, 2, 3]
detections = sv.Detections(...)
detections = detections[np.isin(detections.class_id, class_id)]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by confidence
Allows you to select detections with specific confidence value, for example higher than selected threshold.
=== "After"
```python
import supervision as sv
detections = sv.Detections(...)
detections = detections[detections.confidence > 0.5]
```
<div class="result" markdown>
![by-set-of-classes](https://media.roboflow.com/open-source/supervision/supervision-detection-by-confidence.png){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
detections = sv.Detections(...)
detections = detections[detections.confidence > 0.5]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by area
Allows you to select detections based on their size. We define the area as the number of pixels occupied by the detection in the image. In the example below, we have sifted out the detections that are too small.
=== "After"
```python
import supervision as sv
detections = sv.Detections(...)
detections = detections[detections.area > 1000]
```
<div class="result" markdown>
![by-area](https://media.roboflow.com/open-source/supervision/supervision-detection-by-area.png){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
detections = sv.Detections(...)
detections = detections[detections.area > 1000]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by relative area
Allows you to select detections based on their size in relation to the size of whole image. Sometimes the concept of detection size changes depending on the image. Detection occupying 10000 square px can be large on a 1280x720 image but small on a 3840x2160 image. In such cases, we can filter out detections based on the percentage of the image area occupied by them. In the example below, we remove too large detections.
=== "After"
```python
import supervision as sv
image = ...
height, width, channels = image.shape
image_area = height * width
detections = sv.Detections(...)
detections = detections[(detections.area / image_area) < 0.8]
```
<div class="result" markdown>
![by-relative-area](https://media.roboflow.com/open-source/supervision/supervision-detection-by-relative-area.png?updatedAt=1683207183434){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
image = ...
height, width, channels = image.shape
image_area = height * width
detections = sv.Detections(...)
detections = detections[(detections.area / image_area) < 0.8]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by box dimensions
Allows you to select detections based on their dimensions. The size of the bounding box, as well as its coordinates, can be criteria for rejecting detection. Implementing such filtering requires a bit of custom code but is relatively simple and fast.
=== "After"
```python
import supervision as sv
detections = sv.Detections(...)
w = detections.xyxy[:, 2] - detections.xyxy[:, 0]
h = detections.xyxy[:, 3] - detections.xyxy[:, 1]
detections = detections[(w > 200) & (h > 200)]
```
<div class="result" markdown>
![by-box-dimensions](https://media.roboflow.com/open-source/supervision/supervision-detection-by-box-dimensions.png){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
detections = sv.Detections(...)
w = detections.xyxy[:, 2] - detections.xyxy[:, 0]
h = detections.xyxy[:, 3] - detections.xyxy[:, 1]
detections = detections[(w > 200) & (h > 200)]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by `PolygonZone`
Allows you to use `Detections` in combination with `PolygonZone` to weed out bounding boxes that are in and out of the zone. In the example below you can see how to filter out all detections located in the lower part of the image.
=== "After"
```python
import supervision as sv
zone = sv.PolygonZone(...)
detections = sv.Detections(...)
mask = zone.trigger(detections=detections)
detections = detections[mask]
```
<div class="result" markdown>
![by-polygon-zone](https://media.roboflow.com/open-source/supervision/supervision-detection-by-polygon-zone.png?updatedAt=1683211380445){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
zone = sv.PolygonZone(...)
detections = sv.Detections(...)
mask = zone.trigger(detections=detections)
detections = detections[mask]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
### by mixed conditions
`Detections`' greatest strength, however, is that you can build arbitrarily complex logical conditions by simply combining separate conditions using `&` or `|`.
=== "After"
```python
import supervision as sv
zone = sv.PolygonZone(...)
detections = sv.Detections(...)
mask = zone.trigger(detections=detections)
detections = detections[(detections.confidence > 0.7) & mask]
```
<div class="result" markdown>
![by-mixed-conditions](https://media.roboflow.com/open-source/supervision/supervision-detection-by-mixed-conditions.png){ align=center width="800" }
</div>
=== "Before"
```python
import supervision as sv
zone = sv.PolygonZone(...)
detections = sv.Detections(...)
mask = zone.trigger(detections=detections)
detections = detections[mask]
```
<div class="result" markdown>
![original](https://media.roboflow.com/open-source/supervision/supervision-detection-original.png){ align=center width="800" }
</div>
## Frequently Asked Questions
### How do I filter detections by class in supervision?
Use NumPy-style boolean indexing: `detections[detections.class_id == 0]` for class 0. Combine with `&` or `|` for multiple conditions.
### How do I filter by confidence threshold?
`detections[detections.confidence > 0.5]` returns only detections above the threshold. Chain with class filters for precise results.
### How do I filter by bounding box area?
`detections[detections.area > 1000]` filters by pixel area. If masks are present, `detections.area` uses mask area; otherwise it uses bounding box area from `xyxy`. Use `detections.box_area` when you specifically need bounding box area.
### Can I filter by box aspect ratio or dimensions?
Yes. Use `detections.box_aspect_ratio` for aspect ratio filtering. If you need explicit box dimensions, compute them from `detections.xyxy` as `width = detections.xyxy[:, 2] - detections.xyxy[:, 0]` and `height = detections.xyxy[:, 3] - detections.xyxy[:, 1]`.
### How do I remove duplicate detections (NMS) from my results?
Use `detections.with_nms(threshold=0.5)` — it applies non-maximum suppression on the `xyxy` boxes.
## Author
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
+605
View File
@@ -0,0 +1,605 @@
---
comments: true
description: Load, split, merge, and convert computer vision datasets between YOLO, COCO, Pascal VOC, CreateML, and LabelMe formats using supervision's DetectionDataset.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
date_modified: 2026-06-25
---
With Supervision, you can load and manipulate classification, object detection, and segmentation datasets. This tutorial will walk you through how to load, split, merge, visualize, and augment datasets in Supervision.
## Download Dataset
In this tutorial, we will use a dataset from [Roboflow Universe](https://universe.roboflow.com/), a public repository of thousands of computer vision datasets. If you already have your dataset in [COCO](https://roboflow.com/formats/coco-json), [YOLO](https://roboflow.com/formats/yolov8-pytorch-txt), [Pascal VOC](https://roboflow.com/formats/pascal-voc-xml), [CreateML](https://roboflow.com/formats/createml-json), or [LabelMe](https://roboflow.com/formats/labelme-json) format, you can skip this section.
```bash
pip install roboflow
```
Next, log into your Roboflow account and download the dataset of your choice. The following snippets show common COCO, YOLO, Pascal VOC, and CreateML exports; LabelMe datasets can also be loaded directly from per-image JSON files in the next section. You can customize the code with your workspace ID, project ID, and version number.
=== "COCO"
```python
import roboflow
roboflow.login()
rf = roboflow.Roboflow()
project = rf.workspace("<WORKSPACE_ID>").project("<PROJECT_ID>")
dataset = project.version("<PROJECT_VERSION>").download("coco")
```
=== "YOLO"
```python
import roboflow
roboflow.login()
rf = roboflow.Roboflow()
project = rf.workspace("<WORKSPACE_ID>").project("<PROJECT_ID>")
dataset = project.version("<PROJECT_VERSION>").download("yolov8")
```
=== "Pascal VOC"
```python
import roboflow
roboflow.login()
rf = roboflow.Roboflow()
project = rf.workspace("<WORKSPACE_ID>").project("<PROJECT_ID>")
dataset = project.version("<PROJECT_VERSION>").download("voc")
```
=== "CreateML"
```python
import roboflow
roboflow.login()
rf = roboflow.Roboflow()
project = rf.workspace("<WORKSPACE_ID>").project("<PROJECT_ID>")
dataset = project.version("<PROJECT_VERSION>").download("createml")
```
## Load Dataset
The Supervision library provides convenient functions to load datasets in various formats. If your dataset is already split into train, test, and valid subsets, you can load each of those as separate [`sv.DetectionDataset`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset) instances.
=== "COCO"
We can do so using the [`sv.DetectionDataset.from_coco`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.from_coco) to load annotations in [COCO](https://roboflow.com/formats/coco-json) format.
```python
import supervision as sv
ds_train = sv.DetectionDataset.from_coco(
images_directory_path=f"{dataset.location}/train",
annotations_path=f"{dataset.location}/train/_annotations.coco.json",
)
ds_valid = sv.DetectionDataset.from_coco(
images_directory_path=f"{dataset.location}/valid",
annotations_path=f"{dataset.location}/valid/_annotations.coco.json",
)
ds_test = sv.DetectionDataset.from_coco(
images_directory_path=f"{dataset.location}/test",
annotations_path=f"{dataset.location}/test/_annotations.coco.json",
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
```
=== "YOLO"
We can do so using the [`sv.DetectionDataset.from_yolo`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.from_yolo) to load annotations in [YOLO](https://roboflow.com/formats/yolov8-pytorch-txt) format.
```python
import supervision as sv
ds_train = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/train/images",
annotations_directory_path=f"{dataset.location}/train/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
ds_valid = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/valid/images",
annotations_directory_path=f"{dataset.location}/valid/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
ds_test = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/test/images",
annotations_directory_path=f"{dataset.location}/test/labels",
data_yaml_path=f"{dataset.location}/data.yaml",
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
```
=== "Pascal VOC"
We can do so using the [`sv.DetectionDataset.from_pascal_voc`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.from_pascal_voc) to load annotations in [Pascal VOC](https://roboflow.com/formats/pascal-voc-xml) format.
```python
import supervision as sv
ds_train = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f"{dataset.location}/train/images",
annotations_directory_path=f"{dataset.location}/train/labels",
)
ds_valid = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f"{dataset.location}/valid/images",
annotations_directory_path=f"{dataset.location}/valid/labels",
)
ds_test = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f"{dataset.location}/test/images",
annotations_directory_path=f"{dataset.location}/test/labels",
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
```
=== "CreateML"
We can do so using the [`sv.DetectionDataset.from_createml`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.from_createml) to load annotations in [CreateML](https://roboflow.com/formats/createml-json) format.
```python
import supervision as sv
ds_train = sv.DetectionDataset.from_createml(
images_directory_path=f"{dataset.location}/train",
annotations_path=f"{dataset.location}/train/_annotations.createml.json",
)
ds_valid = sv.DetectionDataset.from_createml(
images_directory_path=f"{dataset.location}/valid",
annotations_path=f"{dataset.location}/valid/_annotations.createml.json",
)
ds_test = sv.DetectionDataset.from_createml(
images_directory_path=f"{dataset.location}/test",
annotations_path=f"{dataset.location}/test/_annotations.createml.json",
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
```
=== "LabelMe"
We can do so using the [`sv.DetectionDataset.from_labelme`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.from_labelme) to load annotations in [LabelMe](https://roboflow.com/formats/labelme-json) format. LabelMe `rectangle` shapes are loaded as bounding boxes and `polygon` shapes are loaded as masks with bounding boxes.
```python
import supervision as sv
ds_train = sv.DetectionDataset.from_labelme(
images_directory_path="<TRAIN_IMAGES_DIRECTORY_PATH>",
annotations_directory_path="<TRAIN_ANNOTATIONS_DIRECTORY_PATH>",
)
ds_valid = sv.DetectionDataset.from_labelme(
images_directory_path="<VALID_IMAGES_DIRECTORY_PATH>",
annotations_directory_path="<VALID_ANNOTATIONS_DIRECTORY_PATH>",
)
ds_test = sv.DetectionDataset.from_labelme(
images_directory_path="<TEST_IMAGES_DIRECTORY_PATH>",
annotations_directory_path="<TEST_ANNOTATIONS_DIRECTORY_PATH>",
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
```
## Split Dataset
If your dataset is not already split into train, test, and valid subsets, you can easily do so using the [`sv.DetectionDataset.split`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.split) method. We can split it as follows, ensuring a random shuffle of the data.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
len(ds)
# 1000
ds_train, ds = ds.split(split_ratio=0.8, shuffle=True)
ds_valid, ds_test = ds.split(split_ratio=0.5, shuffle=True)
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
```
## Merge Dataset
If you have multiple datasets that you would like to merge, you can do so using the [`sv.DetectionDataset.merge`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.merge) method.
=== "COCO"
```{ .py hl_lines="22-28" }
import supervision as sv
ds_train = sv.DetectionDataset.from_coco(
images_directory_path=f'{dataset.location}/train',
annotations_path=f'{dataset.location}/train/_annotations.coco.json',
)
ds_valid = sv.DetectionDataset.from_coco(
images_directory_path=f'{dataset.location}/valid',
annotations_path=f'{dataset.location}/valid/_annotations.coco.json',
)
ds_test = sv.DetectionDataset.from_coco(
images_directory_path=f'{dataset.location}/test',
annotations_path=f'{dataset.location}/test/_annotations.coco.json',
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
ds = sv.DetectionDataset.merge([ds_train, ds_valid, ds_test])
ds.classes
# ['person', 'bicycle', 'car', ...]
len(ds)
# 1000
```
=== "YOLO"
```{ .py hl_lines="25-31" }
import supervision as sv
ds_train = sv.DetectionDataset.from_yolo(
images_directory_path=f'{dataset.location}/train/images',
annotations_directory_path=f'{dataset.location}/train/labels',
data_yaml_path=f'{dataset.location}/data.yaml'
)
ds_valid = sv.DetectionDataset.from_yolo(
images_directory_path=f'{dataset.location}/valid/images',
annotations_directory_path=f'{dataset.location}/valid/labels',
data_yaml_path=f'{dataset.location}/data.yaml'
)
ds_test = sv.DetectionDataset.from_yolo(
images_directory_path=f'{dataset.location}/test/images',
annotations_directory_path=f'{dataset.location}/test/labels',
data_yaml_path=f'{dataset.location}/data.yaml'
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
ds = sv.DetectionDataset.merge([ds_train, ds_valid, ds_test])
ds.classes
# ['person', 'bicycle', 'car', ...]
len(ds)
# 1000
```
=== "Pascal VOC"
```{ .py hl_lines="22-28" }
import supervision as sv
ds_train = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f'{dataset.location}/train/images',
annotations_directory_path=f'{dataset.location}/train/labels'
)
ds_valid = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f'{dataset.location}/valid/images',
annotations_directory_path=f'{dataset.location}/valid/labels'
)
ds_test = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f'{dataset.location}/test/images',
annotations_directory_path=f'{dataset.location}/test/labels'
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
ds = sv.DetectionDataset.merge([ds_train, ds_valid, ds_test])
ds.classes
# ['person', 'bicycle', 'car', ...]
len(ds)
# 1000
```
=== "CreateML"
```{ .py hl_lines="22-28" }
import supervision as sv
ds_train = sv.DetectionDataset.from_createml(
images_directory_path=f'{dataset.location}/train',
annotations_path=f'{dataset.location}/train/_annotations.createml.json',
)
ds_valid = sv.DetectionDataset.from_createml(
images_directory_path=f'{dataset.location}/valid',
annotations_path=f'{dataset.location}/valid/_annotations.createml.json',
)
ds_test = sv.DetectionDataset.from_createml(
images_directory_path=f'{dataset.location}/test',
annotations_path=f'{dataset.location}/test/_annotations.createml.json',
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
ds = sv.DetectionDataset.merge([ds_train, ds_valid, ds_test])
ds.classes
# ['person', 'bicycle', 'car', ...]
len(ds)
# 1000
```
=== "LabelMe"
```{ .py hl_lines="22-28" }
import supervision as sv
ds_train = sv.DetectionDataset.from_labelme(
images_directory_path="<TRAIN_IMAGES_DIRECTORY_PATH>",
annotations_directory_path="<TRAIN_ANNOTATIONS_DIRECTORY_PATH>",
)
ds_valid = sv.DetectionDataset.from_labelme(
images_directory_path="<VALID_IMAGES_DIRECTORY_PATH>",
annotations_directory_path="<VALID_ANNOTATIONS_DIRECTORY_PATH>",
)
ds_test = sv.DetectionDataset.from_labelme(
images_directory_path="<TEST_IMAGES_DIRECTORY_PATH>",
annotations_directory_path="<TEST_ANNOTATIONS_DIRECTORY_PATH>",
)
ds_train.classes
# ['person', 'bicycle', 'car', ...]
len(ds_train), len(ds_valid), len(ds_test)
# 800, 100, 100
ds = sv.DetectionDataset.merge([ds_train, ds_valid, ds_test])
ds.classes
# ['person', 'bicycle', 'car', ...]
len(ds)
# 1000
```
## Iterate over Dataset
There are two ways to loop over a `sv.DetectionDataset`: using a direct [for loop](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.__iter__) called on the `sv.DetectionDataset` instance or loading `sv.DetectionDataset` entries [by index](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.__getitem__).
```python
import supervision as sv
ds = sv.DetectionDataset(...)
# Option 1
for image_path, image, annotations in ds:
... # Process each image and its annotations
# Option 2
for idx in range(len(ds)):
image_path, image, annotations = ds[idx]
... # Process the image and annotations at index `idx`
```
## Visualize Dataset
The Supervision library provides tools for easily visualizing your detection dataset. You can create a grid of annotated images to quickly inspect your data and labels. First, initialize the [`sv.BoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoxAnnotator) and [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.LabelAnnotator). Then, iterate through a subset of the dataset (e.g., the first 25 images), drawing bounding boxes and class labels on each image. Finally, combine the annotated images into a grid for display.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_images = []
for i in range(16):
_, image, annotations = ds[i]
labels = [ds.classes[class_id] for class_id in annotations.class_id]
annotated_image = image.copy()
annotated_image = box_annotator.annotate(annotated_image, annotations)
annotated_image = label_annotator.annotate(annotated_image, annotations, labels)
annotated_images.append(annotated_image)
sv.plot_images_grid(
annotated_images,
grid_size=(4, 4),
)
```
![visualize-dataset](https://media.roboflow.com/supervision-docs/visualize-dataset.png)
## Save Dataset
=== "COCO"
We can do so using the [`sv.DetectionDataset.as_coco`](https://supervision.roboflow.com/datasets/#supervision.dataset.core.DetectionDataset.as_coco) method to save annotations in [COCO](https://roboflow.com/formats/coco-json) format.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
ds.as_coco(
images_directory_path="<IMAGE_DIRECTORY_PATH>",
annotations_path="<ANNOTATIONS_PATH>",
)
```
=== "YOLO"
We can do so using the [`sv.DetectionDataset.as_yolo`](https://supervision.roboflow.com/datasets/#supervision.dataset.core.DetectionDataset.as_yolo) method to save annotations in [YOLO](https://roboflow.com/formats/yolov8-pytorch-txt) format.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
ds.as_yolo(
images_directory_path="<IMAGE_DIRECTORY_PATH>",
annotations_directory_path="<ANNOTATIONS_DIRECTORY_PATH>",
data_yaml_path="<DATA_YAML_PATH>",
)
```
=== "Pascal VOC"
We can do so using the [`sv.DetectionDataset.as_pascal_voc`](https://supervision.roboflow.com/datasets/#supervision.dataset.core.DetectionDataset.as_pascal_voc) method to save annotations in [Pascal VOC](https://roboflow.com/formats/pascal-voc-xml) format.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
ds.as_pascal_voc(
images_directory_path="<IMAGE_DIRECTORY_PATH>",
annotations_directory_path="<ANNOTATIONS_DIRECTORY_PATH>",
)
```
=== "CreateML"
We can do so using the [`sv.DetectionDataset.as_createml`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.as_createml) method to save annotations in [CreateML](https://roboflow.com/formats/createml-json) format.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
ds.as_createml(
images_directory_path="<IMAGE_DIRECTORY_PATH>",
annotations_path="<ANNOTATIONS_PATH>",
)
```
=== "LabelMe"
We can do so using the [`sv.DetectionDataset.as_labelme`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset.as_labelme) method to save annotations in [LabelMe](https://roboflow.com/formats/labelme-json) format. Detections with masks are exported as `polygon` shapes; box-only detections are exported as `rectangle` shapes.
```python
import supervision as sv
ds = sv.DetectionDataset(...)
ds.as_labelme(
images_directory_path="<IMAGE_DIRECTORY_PATH>",
annotations_directory_path="<ANNOTATIONS_DIRECTORY_PATH>",
)
```
## Augment Dataset
In this section, we'll explore using Supervision in combination with Albumentations to augment our dataset. Data augmentation is a common technique in computer vision to increase the size and diversity of training datasets, leading to improved model performance and generalization.
```bash
pip install albumentations
```
Albumentations provides a flexible and powerful API for image augmentation. The core of the library is the [`Compose`](https://albumentations.ai/docs/api-reference/albumentations/core/composition/#Compose) class, which allows you to chain multiple image transformations together. Each transformation is defined using a dedicated class, such as [`HorizontalFlip`](https://albumentations.ai/docs/api-reference/albumentations/augmentations/geometric/flip/#HorizontalFlip), [`RandomBrightnessContrast`](https://albumentations.ai/docs/api-reference/albumentations/augmentations/pixel/transforms/#RandomBrightnessContrast), or [`Perspective`](https://albumentations.ai/docs/api-reference/albumentations/augmentations/geometric/transforms/#Perspective).
```python
import albumentations as A
augmentation = A.Compose(
transforms=[
A.Perspective(p=0.1),
A.HorizontalFlip(p=0.5),
A.RandomBrightnessContrast(p=0.5),
],
bbox_params=A.BboxParams(
format="pascal_voc",
label_fields=["category"],
),
)
```
The key is to set `format='pascal_voc'`, which corresponds to the `[x_min, y_min, x_max, y_max]` bounding box format used in Supervision.
```python
import numpy as np
import supervision as sv
from dataclasses import replace
ds = sv.DetectionDataset(...)
_, original_image, original_annotations = ds[0]
output = augmentation(
image=original_image,
bboxes=original_annotations.xyxy,
category=original_annotations.class_id,
)
augmented_image = output["image"]
augmented_annotations = replace(
original_annotations,
xyxy=np.array(output["bboxes"]),
class_id=np.array(output["category"]),
)
```
![augment-dataset](https://media.roboflow.com/supervision-docs/augment-dataset.png)
## Frequently Asked Questions
### What dataset formats does supervision support?
For detection datasets, supervision supports YOLO, COCO JSON, Pascal VOC, CreateML, and LabelMe. Use `DetectionDataset.from_yolo()`, `from_coco()`, `from_pascal_voc()`, `from_createml()`, or `from_labelme()` to load, and `as_yolo()`, `as_coco()`, `as_pascal_voc()`, `as_createml()`, or `as_labelme()` to save. Classification datasets use `ClassificationDataset.from_folder_structure()` and `as_folder_structure()`.
### Can I split a dataset into train/val/test sets?
`DetectionDataset.split(split_ratio=0.8)` returns exactly two datasets: train (80%) and test (20%). If you need a validation set, split one of those subsets in a separate step.
### Can I merge two datasets together?
Yes. `DetectionDataset.merge([dataset_a, dataset_b])` combines multiple datasets into one. Useful for combining datasets from different sources.
### What augmentations are available?
Common augmentations such as flip, rotate, translate, scale, crop, color jitter, and Gaussian blur can be applied using an external library like Albumentations, as shown in the augmentation example above. Supervision does not provide an `sv.Augmenter` pipeline.
## Author
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
+305
View File
@@ -0,0 +1,305 @@
---
comments: true
description: Save object detection results to CSV or JSON with supervision's CSVSink and JSONSink — export predictions for analysis and downstream pipelines.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
date_modified: 2026-04-22
---
# Save Detections
Supervision enables an easy way to save detections in .CSV and .JSON files for offline processing. This guide demonstrates how to perform video inference using the [Inference](https://github.com/roboflow/inference), [Ultralytics](https://github.com/ultralytics/ultralytics) or [Transformers](https://github.com/huggingface/transformers) packages and save their results with [`sv.CSVSink`](https://supervision.roboflow.com/latest/detection/tools/save_detections/#supervision.detection.tools.csv_sink.CSVSink) and [`sv.JSONSink`](https://supervision.roboflow.com/latest/detection/tools/save_detections/#supervision.detection.tools.json_sink.JSONSink).
## Run Detection
First, you'll need to obtain predictions from your object detection or segmentation model. You can learn more on this topic in our [How to Detect and Annotate](https://supervision.roboflow.com/latest/how_to/detect_and_annotate/) guide.
To generate predictions for saving, initialize your model and iterate over video frames using `sv.get_video_frames_generator`. Each frame is passed to the model, and the raw output is converted into a `sv.Detections` object. This detection loop forms the foundation for both CSV and JSON export workflows shown below.
=== "Inference"
```python
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8n-640")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
for frame in frames_generator:
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
```
=== "Ultralytics"
```python
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
for frame in frames_generator:
results = model(frame)[0]
detections = sv.Detections.from_ultralytics(results)
```
=== "Transformers"
```python
import torch
import supervision as sv
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
for frame in frames_generator:
frame = sv.cv2_to_pillow(frame)
inputs = processor(images=frame, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = frame.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size
)[0]
detections = sv.Detections.from_transformers(results)
```
## Save Detections as CSV
To save detections to a `.CSV` file, open our [`sv.CSVSink`](https://supervision.roboflow.com/latest/detection/tools/save_detections/#supervision.detection.tools.csv_sink.CSVSink) and then pass the [`sv.Detections`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections) object resulting from the inference to it. Its fields are parsed and saved on disk.
=== "Inference"
```{ .py hl_lines="7 12" }
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8n-640")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.CSVSink("<TARGET_CSV_PATH>") as sink:
for frame in frames_generator:
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
sink.append(detections, {})
```
=== "Ultralytics"
```{ .py hl_lines="7 12" }
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.CSVSink("<TARGET_CSV_PATH>") as sink:
for frame in frames_generator:
results = model(frame)[0]
detections = sv.Detections.from_ultralytics(results)
sink.append(detections, {})
```
=== "Transformers"
```{ .py hl_lines="9 23" }
import torch
import supervision as sv
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.CSVSink("<TARGET_CSV_PATH>") as sink:
for frame in frames_generator:
frame = sv.cv2_to_pillow(frame)
inputs = processor(images=frame, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = frame.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers(results)
sink.append(detections, {})
```
| x_min | y_min | x_max | y_max | class_id | confidence | tracker_id | class_name |
| ------- | ------- | ------- | ------- | -------- | ---------- | ---------- | ---------- |
| 2941.14 | 1269.31 | 3220.77 | 1500.67 | 2 | 0.8517 | | car |
| 944.889 | 899.641 | 1235.42 | 1308.80 | 7 | 0.6752 | | truck |
| 1439.78 | 1077.79 | 1621.27 | 1231.40 | 2 | 0.6450 | | car |
## Custom Fields
Besides regular fields in [`sv.Detections`](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections), [`sv.CSVSink`](https://supervision.roboflow.com/latest/detection/tools/save_detections/#supervision.detection.tools.csv_sink.CSVSink) also allows you to add custom information to each row, which can be passed via the `custom_data` dictionary. Let's utilize this feature to save information about the frame index from which the detections originate.
=== "Inference"
```{ .py hl_lines="8 12" }
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8n-640")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.CSVSink("<TARGET_CSV_PATH>") as sink:
for frame_index, frame in enumerate(frames_generator):
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
sink.append(detections, {"frame_index": frame_index})
```
=== "Ultralytics"
```{ .py hl_lines="8 12" }
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.CSVSink("<TARGET_CSV_PATH>") as sink:
for frame_index, frame in enumerate(frames_generator):
results = model(frame)[0]
detections = sv.Detections.from_ultralytics(results)
sink.append(detections, {"frame_index": frame_index})
```
=== "Transformers"
```{ .py hl_lines="10 23" }
import torch
import supervision as sv
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.CSVSink("<TARGET_CSV_PATH>") as sink:
for frame_index, frame in enumerate(frames_generator):
frame = sv.cv2_to_pillow(frame)
inputs = processor(images=frame, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = frame.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers(results)
sink.append(detections, {"frame_index": frame_index})
```
| x_min | y_min | x_max | y_max | class_id | confidence | tracker_id | class_name | frame_index |
| ------- | ------- | ------- | ------- | -------- | ---------- | ---------- | ---------- | ----------- |
| 2941.14 | 1269.31 | 3220.77 | 1500.67 | 2 | 0.8517 | | car | 0 |
| 944.889 | 899.641 | 1235.42 | 1308.80 | 7 | 0.6752 | | truck | 0 |
| 1439.78 | 1077.79 | 1621.27 | 1231.40 | 2 | 0.6450 | | car | 0 |
## Save Detections as JSON
If you prefer to save the result in a `.JSON` file instead of a `.CSV` file, all you need to do is replace [`sv.CSVSink`](https://supervision.roboflow.com/latest/detection/tools/save_detections/#supervision.detection.tools.csv_sink.CSVSink) with [`sv.JSONSink`](https://supervision.roboflow.com/latest/detection/tools/save_detections/#supervision.detection.tools.json_sink.JSONSink).
=== "Inference"
```{ .py hl_lines="7" }
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8n-640")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.JSONSink("<TARGET_JSON_PATH>") as sink:
for frame_index, frame in enumerate(frames_generator):
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
sink.append(detections, {"frame_index": frame_index})
```
=== "Ultralytics"
```{ .py hl_lines="7" }
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.JSONSink("<TARGET_JSON_PATH>") as sink:
for frame_index, frame in enumerate(frames_generator):
results = model(frame)[0]
detections = sv.Detections.from_ultralytics(results)
sink.append(detections, {"frame_index": frame_index})
```
=== "Transformers"
```{ .py hl_lines="9" }
import torch
import supervision as sv
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")
with sv.JSONSink("<TARGET_JSON_PATH>") as sink:
for frame_index, frame in enumerate(frames_generator):
frame = sv.cv2_to_pillow(frame)
inputs = processor(images=frame, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
width, height = frame.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection(
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers(results)
sink.append(detections, {"frame_index": frame_index})
```
## Frequently Asked Questions
### How do I save detections to CSV with supervision?
Open `sv.CSVSink("output.csv")` as a context manager and call `sink.append(detections)` for each frame. The CSV includes box coordinates, confidence, class ID, tracker ID, and any fields stored in `detections.data`.
### Can I save detections to JSON instead?
Yes. Open `sv.JSONSink("output.json")` as a context manager and call `sink.append(detections)` for each frame. The file is written as a JSON array when the context exits.
### Can I add custom fields to the saved output?
Yes. Pass a dict as the second argument: `sink.append(detections, {"frame_index": 5})` — the keys become extra columns in the CSV or extra fields in the JSON.
### Can I save only specific classes or confidence levels?
Filter the `Detections` object before saving: `sink.append(detections[detections.confidence > 0.7])`.
## Author
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
+663
View File
@@ -0,0 +1,663 @@
---
comments: true
description: Track objects across video frames with ByteTrack in supervision — assign persistent IDs and analyze motion from any object detection model.
authors:
- name: Piotr Skalski
role: Computer Vision Engineer, Roboflow
github: https://github.com/SkalskiP
- name: Soumik Mandal
role: ML Engineer, Roboflow
github: https://github.com/soumik12345
date_modified: 2026-04-22
---
# Track Objects
Leverage Supervision's advanced capabilities for enhancing your video analysis by seamlessly [tracking](https://supervision.roboflow.com/latest/trackers/) objects recognized by a multitude of object detection, segmentation and keypoint models. This comprehensive guide will take you through the steps to perform inference using the YOLOv8 model via either the [Inference](https://github.com/roboflow/inference) or [Ultralytics](https://github.com/ultralytics/ultralytics) packages. Following this, you'll discover how to track these objects efficiently and annotate your video content for a deeper analysis.
## Object Detection & Segmentation
To make it easier for you to follow our tutorial download the video we will use as an example. You can do this using the [`supervision.assets`](https://supervision.roboflow.com/latest/assets/) module included in the base package.
This section demonstrates how to detect and segment objects in video frames using YOLOv8 with either the Inference or Ultralytics package. You will download a sample video, define a per-frame callback function that runs model prediction, and process the entire video to produce an annotated output file.
```python
from supervision.assets import download_assets, VideoAssets
download_assets(VideoAssets.PEOPLE_WALKING)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/people-walking.mp4" type="video/mp4">
</video>
### Run Inference
First, you'll need to obtain predictions from your object detection or segmentation model. In this tutorial, we are using the YOLOv8 model as an example. However, Supervision is versatile and compatible with various models. Check this [link](https://supervision.roboflow.com/latest/how_to/detect_and_annotate/#load-predictions-into-supervision) for guidance on how to plug in other models.
We will define a `callback` function, which will process each frame of the video by obtaining model predictions and then annotating the frame based on these predictions. This `callback` function will be essential in the subsequent steps of the tutorial, as it will be modified to include tracking, labeling, and trace annotations.
!!! tip
Both object detection and segmentation models are supported. Try it with `yolov8n.pt` or `yolov8n-640-seg`!
=== "Ultralytics"
```{ .py }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model(frame)[0]
detections = sv.Detections.from_ultralytics(results)
return box_annotator.annotate(frame.copy(), detections=detections)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(model_id="yolov8n-640", api_key="<ROBOFLOW_API_KEY>")
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
detections = sv.Detections.from_inference(results)
return box_annotator.annotate(frame.copy(), detections=detections)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/run-inference.mp4" type="video/mp4">
</video>
### Tracking
After running inference and obtaining predictions, the next step is to track the detected objects throughout the video. Utilizing Supervisions [`sv.ByteTrack`](https://supervision.roboflow.com/latest/trackers/#supervision.tracker.byte_tracker.core.ByteTrack) functionality, each detected object is assigned a unique tracker ID, enabling the continuous following of the object's motion path across different frames.
!!! warning "Deprecated tracker wrapper"
`sv.ByteTrack` is deprecated in favor of `ByteTrackTracker` from the external `trackers` package. The external tracker uses `update()` instead of `update_with_detections()`.
=== "Ultralytics"
```{ .py hl_lines="6 12" }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
tracker = sv.ByteTrack()
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model(frame)[0]
detections = sv.Detections.from_ultralytics(results)
detections = tracker.update_with_detections(detections)
return box_annotator.annotate(frame.copy(), detections=detections)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="6 12" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(model_id="yolov8n-640", api_key="<ROBOFLOW_API_KEY>")
tracker = sv.ByteTrack()
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
detections = sv.Detections.from_inference(results)
detections = tracker.update_with_detections(detections)
return box_annotator.annotate(frame.copy(), detections=detections)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
### Annotate Video with Tracking IDs
Annotating the video with tracking IDs helps in distinguishing and following each object distinctly. With the [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.LabelAnnotator) in Supervision, we can overlay the tracker IDs and class labels on the detected objects, offering a clear visual representation of each object's class and unique identifier.
=== "Ultralytics"
```{ .py hl_lines="8 15-19 23-24" }
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()
def callback(frame: np.ndarray, _: 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.data["class_name"], detections.tracker_id)
]
annotated_frame = box_annotator.annotate(
frame.copy(), detections=detections)
return label_annotator.annotate(
annotated_frame, detections=detections, labels=labels)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="8 15-19 23-24" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(model_id="yolov8n-640", api_key="<ROBOFLOW_API_KEY>")
tracker = sv.ByteTrack()
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
detections = sv.Detections.from_inference(results)
detections = tracker.update_with_detections(detections)
labels = [
f"#{tracker_id} {class_name}"
for class_name, tracker_id
in zip(detections.data["class_name"], detections.tracker_id)
]
annotated_frame = box_annotator.annotate(
frame.copy(), detections=detections)
return label_annotator.annotate(
annotated_frame, detections=detections, labels=labels)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/annotate-video-with-tracking-ids.mp4" type="video/mp4">
</video>
### Annotate Video with Traces
Adding traces to the video involves overlaying the historical paths of the detected objects. This feature, powered by the [`sv.TraceAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.TraceAnnotator), allows for visualizing the trajectories of objects, helping in understanding the movement patterns and interactions between objects in the video.
=== "Ultralytics"
```{ .py hl_lines="9 26-27" }
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, _: 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.data["class_name"], detections.tracker_id)
]
annotated_frame = box_annotator.annotate(
frame.copy(), detections=detections)
annotated_frame = label_annotator.annotate(
annotated_frame, detections=detections, labels=labels)
return trace_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="9 26-27" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(model_id="yolov8n-640", api_key="<ROBOFLOW_API_KEY>")
tracker = sv.ByteTrack()
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
trace_annotator = sv.TraceAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
detections = sv.Detections.from_inference(results)
detections = tracker.update_with_detections(detections)
labels = [
f"#{tracker_id} {class_name}"
for class_name, tracker_id
in zip(detections.data["class_name"], detections.tracker_id)
]
annotated_frame = box_annotator.annotate(
frame.copy(), detections=detections)
annotated_frame = label_annotator.annotate(
annotated_frame, detections=detections, labels=labels)
return trace_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="people-walking.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/annotate-video-with-traces.mp4" type="video/mp4">
</video>
## Keypoints
Models aren't limited to object detection and segmentation. Keypoint detection allows for detailed analysis of body joints and connections, especially valuable for applications like human pose estimation. This section introduces keypoint tracking. We'll walk through the steps of annotating keypoints, converting them into bounding box detections compatible with `ByteTrack`, and applying detection smoothing for enhanced stability.
To make it easier for you to follow our tutorial, let's download the video we will use as an example. You can do this using the [`supervision.assets`](https://supervision.roboflow.com/latest/assets/) module included in the base package.
```python
from supervision.assets import download_assets, VideoAssets
download_assets(VideoAssets.SKIING)
```
<video controls muted>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/skiing-hd.mp4" type="video/mp4">
</video>
### Keypoint Detection
First, you'll need to obtain predictions from your keypoint detection model. In this tutorial, we are using the YOLOv8 model as an example. However, Supervision is versatile and compatible with various models. Check this [link](https://supervision.roboflow.com/latest/keypoint/core/) for guidance on how to plug in other models.
We will define a `callback` function, which will process each frame of the video by obtaining model predictions and then annotating the frame based on these predictions.
Let's immediately visualize the results with our [`EdgeAnnotator`](https://supervision.roboflow.com/latest/keypoint/annotators/#supervision.key_points.annotators.EdgeAnnotator) and [`VertexAnnotator`](https://supervision.roboflow.com/latest/keypoint/annotators/#supervision.key_points.annotators.VertexAnnotator).
=== "Ultralytics"
```{ .py hl_lines="5 10-11" }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8m-pose.pt")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model(frame)[0]
key_points = sv.KeyPoints.from_ultralytics(results)
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
return vertex_annotator.annotate(
annotated_frame, key_points=key_points)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="5-6 11-12" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(
model_id="yolov8m-pose-640", api_key="<ROBOFLOW_API_KEY>")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
key_points = sv.KeyPoints.from_inference(results)
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
return vertex_annotator.annotate(
annotated_frame, key_points=key_points)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/track-keypoints-only-keypoints.mp4" type="video/mp4">
</video>
### Convert to Detections
Keypoint tracking is currently supported via the conversion of `KeyPoints` to `Detections`. This is achieved with the [`KeyPoints.as_detections()`](https://supervision.roboflow.com/latest/keypoint/core/#supervision.key_points.core.KeyPoints.as_detections) function.
Let's convert to detections and visualize the results with our [`BoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoxAnnotator).
!!! tip
You may use the `selected_keypoint_indices` argument to specify a subset of keypoints to convert. This is useful when some keypoints could be occluded. For example: a person might swing their arm, causing the elbow to be occluded by the torso sometimes.
=== "Ultralytics"
```{ .py hl_lines="8 13 19-20" }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8m-pose.pt")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model(frame)[0]
key_points = sv.KeyPoints.from_ultralytics(results)
detections = key_points.as_detections()
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
annotated_frame = vertex_annotator.annotate(
annotated_frame, key_points=key_points)
return box_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="9 14 20-21" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(
model_id="yolov8m-pose-640", api_key="<ROBOFLOW_API_KEY>")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
key_points = sv.KeyPoints.from_inference(results)
detections = key_points.as_detections()
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
annotated_frame = vertex_annotator.annotate(
annotated_frame, key_points=key_points)
return box_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/track-keypoints-converted-to-detections.mp4" type="video/mp4">
</video>
### Keypoint Tracking
Now that we have a `Detections` object, we can track it throughout the video. Utilizing Supervision's [`sv.ByteTrack`](https://supervision.roboflow.com/latest/trackers/#supervision.tracker.byte_tracker.core.ByteTrack) functionality, each detected object is assigned a unique tracker ID, enabling the continuous following of the object's motion path across different frames. We shall visualize the result with `TraceAnnotator`.
=== "Ultralytics"
```{ .py hl_lines="10-11 17 25-26" }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8m-pose.pt")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
box_annotator = sv.BoxAnnotator()
tracker = sv.ByteTrack()
trace_annotator = sv.TraceAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model(frame)[0]
key_points = sv.KeyPoints.from_ultralytics(results)
detections = key_points.as_detections()
detections = tracker.update_with_detections(detections)
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
annotated_frame = vertex_annotator.annotate(
annotated_frame, key_points=key_points)
annotated_frame = box_annotator.annotate(
annotated_frame, detections=detections)
return trace_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="11-12 18 26-27" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(
model_id="yolov8m-pose-640", api_key="<ROBOFLOW_API_KEY>")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
box_annotator = sv.BoxAnnotator()
tracker = sv.ByteTrack()
trace_annotator = sv.TraceAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
key_points = sv.KeyPoints.from_inference(results)
detections = key_points.as_detections()
detections = tracker.update_with_detections(detections)
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
annotated_frame = vertex_annotator.annotate(
annotated_frame, key_points=key_points)
annotated_frame = box_annotator.annotate(
annotated_frame, detections=detections)
return trace_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/track-keypoints-with-tracking.mp4" type="video/mp4">
</video>
### Bonus: Smoothing
We could stop here as we have successfully tracked the object detected by the keypoint model. However, we can further enhance the stability of the boxes by applying [`DetectionsSmoother`](https://supervision.roboflow.com/latest/detection/tools/smoother/). This tool helps in stabilizing the boxes by smoothing the bounding box coordinates across frames. It is very simple to use:
=== "Ultralytics"
```{ .py hl_lines="11 19" }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8m-pose.pt")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
box_annotator = sv.BoxAnnotator()
tracker = sv.ByteTrack()
smoother = sv.DetectionsSmoother()
trace_annotator = sv.TraceAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model(frame)[0]
key_points = sv.KeyPoints.from_ultralytics(results)
detections = key_points.as_detections()
detections = tracker.update_with_detections(detections)
detections = smoother.update_with_detections(detections)
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
annotated_frame = vertex_annotator.annotate(
annotated_frame, key_points=key_points)
annotated_frame = box_annotator.annotate(
annotated_frame, detections=detections)
return trace_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
=== "Inference"
```{ .py hl_lines="12 20" }
import numpy as np
import supervision as sv
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(
model_id="yolov8m-pose-640", api_key="<ROBOFLOW_API_KEY>")
edge_annotator = sv.EdgeAnnotator()
vertex_annotator = sv.VertexAnnotator()
box_annotator = sv.BoxAnnotator()
tracker = sv.ByteTrack()
smoother = sv.DetectionsSmoother()
trace_annotator = sv.TraceAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
results = model.infer(frame)[0]
key_points = sv.KeyPoints.from_inference(results)
detections = key_points.as_detections()
detections = tracker.update_with_detections(detections)
detections = smoother.update_with_detections(detections)
annotated_frame = edge_annotator.annotate(
frame.copy(), key_points=key_points)
annotated_frame = vertex_annotator.annotate(
annotated_frame, key_points=key_points)
annotated_frame = box_annotator.annotate(
annotated_frame, detections=detections)
return trace_annotator.annotate(
annotated_frame, detections=detections)
sv.process_video(
source_path="skiing.mp4",
target_path="result.mp4",
callback=callback
)
```
<video controls>
<source src="https://media.roboflow.com/supervision/video-examples/how-to/track-objects/track-keypoints-with-smoothing.mp4" type="video/mp4">
</video>
This structured walkthrough should give a detailed pathway to annotate videos effectively using Supervisions various functionalities, including object tracking and trace annotations.
## Frequently Asked Questions
### How do I track objects across video frames with supervision?
Pass `Detections` to `sv.ByteTrack.update_with_detections()` on each frame. The tracker assigns persistent IDs. Combine with `sv.TraceAnnotator` to visualize trajectories. `sv.ByteTrack` is deprecated in favor of `ByteTrackTracker` from the `trackers` package, where the update method is named `update()`.
### What should I know about ByteTrack?
ByteTrack uses low-confidence detections during association, which can improve continuity during missed or weak detections. Supervision's built-in `ByteTrack` wrapper is deprecated in favor of the external `trackers` package.
### Can I track instances instead of bounding boxes?
Yes. ByteTrack tracks bounding boxes. For instance masks, use `sv.MaskAnnotator` with the tracker IDs to color-code each tracked object consistently.
### Does ByteTrack work with any detection model?
Yes. ByteTrack is model-agnostic - it accepts any `Detections` object with bounding boxes, regardless of the supported converter or model output that produced it.
## Authors
- [Piotr Skalski](https://github.com/SkalskiP) — Computer Vision Engineer, Roboflow
- [Soumik Mandal](https://github.com/soumik12345) — ML Engineer, Roboflow
+193
View File
@@ -0,0 +1,193 @@
---
comments: true
description: Use CompactMask for memory-efficient instance segmentation in supervision — ingest COCO RLE payloads, skip mask materialisation, and merge mixed dense and compact detections without allocating a full pixel stack.
authors:
- name: Borda
role: Open Source Engineer, Roboflow
github: https://github.com/borda
date_modified: 2026-07-01
---
# Use Compact Masks for Memory-Efficient Segmentation
[CompactMask][supervision.detection.compact_mask.CompactMask] stores each instance mask as a run-length encoding of its bounding-box **crop** rather than a full `(H, W)` boolean frame. For high-resolution images with many sparse masks this can reduce memory from tens of gigabytes to tens of megabytes, and eliminates full-frame decode work in annotators that only need the cropped region.
!!! Note
`sv.mask_to_xyxy` keeps supervision's inclusive max-coordinate convention for compatibility with `CompactMask` and current box-based adapters. Use `sv.mask_to_roi` when you need exclusive slice bounds for NumPy indexing or crop extraction.
This guide covers the four main integration points:
1. [Ingesting COCO RLE payloads directly as CompactMask](#ingest-coco-rle-payloads)
2. [Parsing Roboflow Inference results without a dense stack](#parse-inference-results)
3. [Skipping mask materialisation for box/label annotators](#skip-unnecessary-materialisation)
4. [Merging mixed dense and compact detections](#merge-mixed-detections)
---
## Ingest COCO RLE Payloads
If your model or API returns masks in the COCO RLE format (`{"size": [H, W], "counts": "..."}`) you can convert them directly to `CompactMask` without allocating an `(N, H, W)` boolean array:
```python
import numpy as np
import supervision as sv
from supervision.detection.compact_mask import CompactMask
# Example: two COCO RLE masks for a 720×1280 frame.
# Replace the counts strings with actual compressed RLE payloads from your
# model or API — e.g., from pycocotools mask.encode() or an Inference response.
rles = [
{"size": [720, 1280], "counts": "YOUR_RLE_COUNTS_STRING_HERE"},
{"size": [720, 1280], "counts": "YOUR_RLE_COUNTS_STRING_HERE"},
]
xyxy = np.array(
[
[100.0, 50.0, 400.0, 300.0],
[500.0, 200.0, 900.0, 600.0],
]
)
compact = CompactMask.from_coco_rle(rles, xyxy, image_shape=(720, 1280))
detections = sv.Detections(
xyxy=xyxy,
mask=compact,
class_id=np.array([0, 1]),
)
```
`from_coco_rle` uses run-length arithmetic scoped to each bounding box so no dense pixel array is ever created. Uncompressed integer count lists are also accepted in place of compressed strings.
---
## Parse Inference Results
`Detections.from_inference` accepts a `compact_masks=True` flag that routes the Roboflow RLE payload through `CompactMask.from_coco_rle` instead of decoding to a dense stack:
```python
import supervision as sv
# result: a Roboflow Inference v2 response dict with instance masks.
detections = sv.Detections.from_inference(result, compact_masks=True)
from supervision.detection.compact_mask import CompactMask
assert isinstance(detections.mask, CompactMask)
```
!!! Warning
`compact_masks=True` crops each mask to its detector bounding box. Pixels outside the box are silently dropped. For masks that extend meaningfully beyond the reported bounding box, use the default `compact_masks=False` (dense decode) to preserve all pixels.
To convert an existing dense-mask `Detections` to compact at any point:
```python
detections_compact = detections.to_compact_masks()
```
---
## Skip Unnecessary Materialisation
Annotators that do not draw masks (box, label, circle, ellipse, trace, keypoint) expose `requires_mask = False`. Integrations can branch on this flag to avoid decoding compact or RLE masks before annotation:
```python
import supervision as sv
annotators = [
sv.BoxAnnotator(),
sv.LabelAnnotator(),
sv.MaskAnnotator(), # requires_mask = True
]
for ann in annotators:
if ann.requires_mask:
# Annotator reads mask pixels — CompactMask decodes lazily per crop.
scene = ann.annotate(scene, detections)
else:
# Annotator ignores masks — strip mask field to eliminate any decode cost.
det_no_mask = sv.Detections(
xyxy=detections.xyxy,
confidence=detections.confidence,
class_id=detections.class_id,
)
scene = ann.annotate(scene, det_no_mask)
```
Annotators that set `requires_mask = True`: [MaskAnnotator][supervision.annotators.core.MaskAnnotator], [PolygonAnnotator][supervision.annotators.core.PolygonAnnotator], [HaloAnnotator][supervision.annotators.core.HaloAnnotator].
All others default to `requires_mask = False`.
!!! Note
`PolygonAnnotator` and `MaskAnnotator` both operate directly on `CompactMask` without materialising the full `(N, H, W)` frame — passing compact detections to them is already efficient.
---
## Merge Mixed Detections
When merging `Detections` objects that mix dense `ndarray` masks and `CompactMask` instances, `Detections.merge` converts dense inputs to `CompactMask` automatically. No full `(N, H, W)` stack is allocated:
```python
import numpy as np
import supervision as sv
from supervision.detection.compact_mask import CompactMask
H, W = 720, 1280
# Compact detections from an RLE-based source.
# Replace the counts string with a real compressed RLE payload from your model or API.
rles = [{"size": [H, W], "counts": "YOUR_RLE_COUNTS_STRING_HERE"}]
xyxy_a = np.array([[100.0, 50.0, 400.0, 300.0]])
cm = CompactMask.from_coco_rle(rles, xyxy_a, image_shape=(H, W))
det_a = sv.Detections(xyxy=xyxy_a, mask=cm, class_id=np.array([0]))
# Dense detections from a different source.
masks_b = np.zeros((1, H, W), dtype=bool)
masks_b[0, 200:400, 500:800] = True
xyxy_b = np.array([[500.0, 200.0, 799.0, 399.0]])
det_b = sv.Detections(xyxy=xyxy_b, mask=masks_b, class_id=np.array([1]))
# Output is CompactMask regardless of input order.
merged = sv.Detections.merge([det_a, det_b])
assert isinstance(merged.mask, CompactMask)
assert len(merged) == 2
```
Merge rules:
| Inputs | Output mask type |
| ------------------------------------- | ------------------------------- |
| All `CompactMask` | `CompactMask` |
| Mixed `CompactMask` + dense `ndarray` | `CompactMask` |
| All dense `ndarray` | `ndarray` (backward compatible) |
All `CompactMask` inputs must share the same `image_shape`; mismatches raise `ValueError`.
---
## Performance Notes
These estimates apply to the **parsing and annotation stage**, not end-to-end pipeline FPS. Model inference typically dominates total runtime.
| Optimisation | Realistic gain | Applies when |
| ---------------------------- | -------------------------- | ------------------------------------------------------------- |
| `from_coco_rle` ingestion | 2560% faster parse | Full-frame COCO RLE payload; current dense decode path |
| `MaskAnnotator` ROI blending | 1035% faster annotation | Many small, sparse masks on high-res frames |
| `PolygonAnnotator` crop path | 1545% faster polygon draw | Many compact masks; full-frame materialise was the bottleneck |
| Mixed-mask merge | 520% faster merge | Mix of compact and dense sources (e.g. multi-camera stitch) |
Upper-end gains assume: ≥1080p frames, tens to hundreds of instances, masks covering less than ~20% of total pixels.
---
## API Reference
- [CompactMask][supervision.detection.compact_mask.CompactMask]
- [CompactMask.from_coco_rle][supervision.detection.compact_mask.CompactMask.from_coco_rle]
- [CompactMask.from_dense][supervision.detection.compact_mask.CompactMask.from_dense]
- [Detections.from_inference][supervision.detection.core.Detections.from_inference]
- [Detections.to_compact_masks][supervision.detection.core.Detections.to_compact_masks]
- [Detections.merge][supervision.detection.core.Detections.merge]
- [BaseAnnotator.requires_mask][supervision.annotators.base.BaseAnnotator]
+192
View File
@@ -0,0 +1,192 @@
---
template: index.html
comments: true
hide:
- navigation
- toc
description: Open-source Python library providing computer vision tools for annotating detections, tracking objects, counting in zones, and processing datasets.
---
<div class="md-typeset">
<h1></h1>
</div>
<div align="center" id="logo" style="padding-top: 1rem;">
<a align="center" href="" target="_blank">
<img width="850"
src="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png?updatedAt=1678995927529">
</a>
</div>
<style>
#hello {
margin: 0;
}
</style>
## What is Supervision?
Supervision is an open-source Python library by Roboflow for building computer vision applications. It provides a unified `Detections` object with converters for supported outputs from Ultralytics, Roboflow Inference, Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers.
With Supervision you can annotate images and video with bounding boxes, masks, and labels; track objects across frames with persistent IDs; count and filter detections inside polygon zones; load and convert datasets between YOLO, COCO, and Pascal VOC formats; and benchmark model performance with mAP and confusion matrices.
Supervision is MIT licensed, has 38,000+ GitHub stars, and over 1 million monthly PyPI downloads. It is developed in public on GitHub for production computer vision workflows.
## 👋 Hello
We write your reusable computer vision tools. Whether you need to load your dataset from your hard drive, draw detections on an image or video, or count how many detections are in a zone. You can count on us!
<video controls>
<source
src="https://media.roboflow.com/traffic_analysis_result.mp4"
type="video/mp4"
>
</video>
## 💻 Install
You can install `supervision` in a [**Python>=3.10**](https://www.python.org/) environment.
!!! example "Installation"
=== "pip (recommended)"
[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision) [![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision) [![license](https://img.shields.io/pypi/l/supervision)](../LICENSE.md) [![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)
```bash
pip install supervision
```
=== "poetry"
[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision) [![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision) [![license](https://img.shields.io/pypi/l/supervision)](../LICENSE.md) [![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)
```bash
poetry add supervision
```
=== "uv"
[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision) [![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision) [![license](https://img.shields.io/pypi/l/supervision)](../LICENSE.md) [![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)
```bash
uv pip install supervision
```
For uv projects:
```bash
uv add supervision
```
=== "rye"
[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision) [![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision) [![license](https://img.shields.io/pypi/l/supervision)](../LICENSE.md) [![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)
```bash
rye add supervision
```
!!! example "conda/mamba install"
=== "conda"
[![conda-recipe](https://img.shields.io/badge/recipe-supervision-green.svg)](https://anaconda.org/conda-forge/supervision) [![conda-downloads](https://img.shields.io/conda/dn/conda-forge/supervision.svg)](https://anaconda.org/conda-forge/supervision) [![conda-version](https://img.shields.io/conda/vn/conda-forge/supervision.svg)](https://anaconda.org/conda-forge/supervision) [![conda-platforms](https://img.shields.io/conda/pn/conda-forge/supervision.svg)](https://anaconda.org/conda-forge/supervision)
```bash
conda install -c conda-forge supervision
```
=== "mamba"
[![mamba-recipe](https://img.shields.io/badge/recipe-supervision-green.svg)](https://anaconda.org/conda-forge/supervision) [![mamba-downloads](https://img.shields.io/conda/dn/conda-forge/supervision.svg)](https://anaconda.org/conda-forge/supervision) [![mamba-version](https://img.shields.io/conda/vn/conda-forge/supervision.svg)](https://anaconda.org/conda-forge/supervision) [![mamba-platforms](https://img.shields.io/conda/pn/conda-forge/supervision.svg)](https://anaconda.org/conda-forge/supervision)
```bash
mamba install -c conda-forge supervision
```
!!! example "git clone (for development)"
=== "virtualenv"
```bash
# clone repository and navigate to root directory
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
cd supervision
# setup python environment and activate it
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
# installation
pip install -e "."
```
=== "uv"
```bash
# clone repository and navigate to root directory
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
cd supervision
# setup python environment and activate it
uv venv
source .venv/bin/activate
# installation
uv pip install -r pyproject.toml -e . --all-extras
```
## 🚀 Quickstart
<div class="grid cards" markdown>
- **Detect and Annotate**
---
Annotate predictions from a range of object detection and segmentation models
[:octicons-arrow-right-24: Tutorial](how_to/detect_and_annotate.md)
- **Track Objects**
---
Discover how to enhance video analysis by implementing seamless object tracking
[:octicons-arrow-right-24: Tutorial](how_to/track_objects.md)
- **Detect Small Objects**
---
Learn how to detect small objects in images
[:octicons-arrow-right-24: Tutorial](how_to/detect_small_objects.md)
- **Count Objects Crossing Line**
---
Explore methods to accurately count and analyze objects crossing a predefined line
[:octicons-arrow-right-24: Notebook](https://supervision.roboflow.com/latest/notebooks/count-objects-crossing-the-line/)
- > **Filter Objects in Zone**
---
Master the techniques to selectively filter and focus on objects within a specific zone
- **Cheatsheet**
---
Access a quick reference guide to the most common `supervision` functions
[:octicons-arrow-right-24: Cheatsheet](https://roboflow.github.io/cheatsheet-supervision/)
</div>
+143
View File
@@ -0,0 +1,143 @@
document.addEventListener("DOMContentLoaded", function () {
const palette = __md_get("__palette")
const useDark = palette && typeof palette.color === "object" && palette.color.scheme === "slate"
const theme = useDark ? "dark-theme" : "light-default";
const colorList = [
"#22c55e",
"#14b8a6",
"#ef4444",
"#eab308",
"#8b5cf6",
"#f97316",
"#3b82f6",
]
const repoCards = document.querySelectorAll(".repo-card");
const labelsAll = Array
.from(repoCards)
.flatMap((element) => element.getAttribute('data-labels').split(','))
.map(label => label.trim())
.filter(label => label !== '');
const uniqueLabels = [...new Set(labelsAll)];
const labelToColor = uniqueLabels.reduce((map, label, index) => {
map[label] = colorList[index % colorList.length];
return map;
}, {});
async function renderCard(element, elementIndex) {
const name = element.getAttribute('data-name');
const labels = element.getAttribute('data-labels');
const version = element.getAttribute('data-version');
const authors = element.getAttribute('data-author');
const labelHTML = labels ? labels.split(',').filter(label => label !== '').map((label, index) => {
const color = labelToColor[label.trim()];
return `
<span
class="label non-selectable-text"
style="background-color: ${color}"
>
${label.trim()}
</span>
`;
}).join(' ') : '';
const authorArray = authors.split(',');
const authorDataArray = await Promise.all(authorArray.map(async (author) => {
const response = await fetch(`https://api.github.com/users/${author.trim()}`);
return await response.json();
}));
let authorAvatarsHTML = authorDataArray.map((authorData, index) => {
const marginLeft = index === 0 ? '0' : '-10px';
const zIndex = 4 - index;
return `
<div
class="author-container"
data-login="${authorData.login}-${elementIndex}"
style="margin-left: ${marginLeft};"
>
<a
href="https://github.com/${authorData.login}"
target="_blank"
style="line-height: 0;"
>
<img
class="author-avatar"
src="${authorData.avatar_url}"
alt="${authorData.login}'s avatar"
>
</a>
</div>
`;
}).join('');
let authorNamesHTML = authorDataArray.map(
authorData => `
<span
class="author-name"
data-login="${authorData.login}-${elementIndex}"
style="color: ${theme.color}"
>
<a href="https://github.com/${authorData.login}" target="_blank">
${authorData.login}
</a>
</span>`
).join(',&nbsp;');
let authorsHTML = `
<div class="authors" style="margin: 0;">
${authorAvatarsHTML}
<div class="author-names">${authorNamesHTML}</div>
</div>
`;
element.innerText = `
<div style="
display: grid !important;
grid-template-rows: auto;
height: 100%;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji; background: ${theme.background}; font-size: 14px; line-height: 1.5; color: ${theme.color}">
<div style="display: flex; align-items: center;">
<span style="font-weight: 700; font-size: 1rem; color: ${theme.linkColor};">
${name}
</span>
</div>
${authorsHTML}
<div style="font-size: 12px; color: ${theme.color}; display: grid; grid-template-columns: auto 3fr; justify-content: space-between; gap: 1rem;">
<div style="display: flex; align-items: center;">
<img src="/assets/supervision-lenny.png" aria-label="stars" width="20" height="20" role="img" />
&nbsp;
<span style="margin-left: 4px">${version}</span>
</div>
<div style="display: flex; align-items: center; flex-wrap: wrap; align-content: right;
gap: 0.1rem;">
${labelHTML}
</div>
</div>
</div>
`;
let sanitizedHTML = DOMPurify.sanitize(element.innerText);
element.innerHTML = sanitizedHTML;
document.querySelectorAll('.author-name').forEach(element => {
element.addEventListener('mouseenter', function () {
const login = this.getAttribute('data-login');
document.querySelector(`.author-container[data-login="${login}"]`).classList.add('hover');
});
element.addEventListener('mouseleave', function () {
const login = this.getAttribute('data-login');
document.querySelector(`.author-container[data-login="${login}"]`).classList.remove('hover');
});
});
}
repoCards.forEach((element, index) => {
renderCard(element, index);
});
})
+10
View File
@@ -0,0 +1,10 @@
document.addEventListener("DOMContentLoaded", function () {
var script = document.createElement("script");
script.src = "https://widget.kapa.ai/kapa-widget.bundle.js";
script.setAttribute("data-website-id", "e83c5c60-2968-410b-a2da-08fb104f23df");
script.setAttribute("data-project-name", "Roboflow");
script.setAttribute("data-project-color", "#6405C9");
script.setAttribute("data-project-logo", "https://media.roboflow.com/chat.png");
script.async = true;
document.head.appendChild(script);
});
+19
View File
@@ -0,0 +1,19 @@
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]],
processEscapes: true,
processEnvironments: true
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex"
}
};
document$.subscribe(() => {
MathJax.startup.output.clearCache()
MathJax.typesetClear()
MathJax.texReset()
MathJax.typesetPromise()
})
+197
View File
@@ -0,0 +1,197 @@
/**
* Custom copy handler for Python console (pycon) code blocks.
* Strips >>> and ... prompts when copying code examples.
*/
document.addEventListener("DOMContentLoaded", function () {
const COPY_BUTTON_SELECTOR = ".md-clipboard, .md-code__button";
function handleCopyButtonClick(event) {
const copyButton = event.target.closest(COPY_BUTTON_SELECTOR);
if (!copyButton) return;
const codeBlock = findCodeBlockForCopyButton(copyButton);
if (!codeBlock) return;
const rawText = codeBlock.textContent || "";
if (!shouldStripPrompts(codeBlock, rawText)) return;
const strippedText = stripPythonPrompts(rawText);
primeClipboardButton(copyButton, strippedText);
}
function handleCopyButtonPointerDown(event) {
const copyButton = event.target.closest(COPY_BUTTON_SELECTOR);
if (!copyButton) return;
const codeBlock = findCodeBlockForCopyButton(copyButton);
if (!codeBlock) return;
const rawText = codeBlock.textContent || "";
if (!shouldStripPrompts(codeBlock, rawText)) return;
const strippedText = stripPythonPrompts(rawText);
primeClipboardButton(copyButton, strippedText);
}
function handleSelectionCopy(event) {
const selection = window.getSelection();
if (!selection || selection.rangeCount === 0) return;
const range = selection.getRangeAt(0);
const anchorNode = range.commonAncestorContainer;
const codeBlock =
anchorNode.nodeType === Node.ELEMENT_NODE
? anchorNode.closest("code")
: anchorNode.parentElement?.closest("code");
if (!codeBlock) return;
const rawText = selection.toString();
if (!shouldStripPrompts(codeBlock, rawText)) return;
event.preventDefault();
event.stopPropagation();
const strippedText = stripPythonPrompts(rawText);
event.clipboardData?.setData("text/plain", strippedText);
}
function bindCopyButtons(root) {
root
.querySelectorAll(COPY_BUTTON_SELECTOR)
.forEach((button) => {
button.removeEventListener("click", handleCopyButtonClick, true);
button.addEventListener("click", handleCopyButtonClick, true);
button.removeEventListener(
"pointerdown",
handleCopyButtonPointerDown,
true
);
button.addEventListener(
"pointerdown",
handleCopyButtonPointerDown,
true
);
});
}
function observeDynamicCopyButtons() {
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type !== "childList") continue;
mutation.addedNodes.forEach((node) => {
if (node.nodeType !== Node.ELEMENT_NODE) return;
if (node.matches?.(COPY_BUTTON_SELECTOR)) {
bindCopyButtons(node.parentElement || document);
return;
}
if (node.querySelectorAll) {
const hasButtons = node.querySelectorAll(COPY_BUTTON_SELECTOR);
if (hasButtons.length > 0) {
bindCopyButtons(node);
}
}
});
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
document.addEventListener("click", handleCopyButtonClick, true);
document.addEventListener("pointerdown", handleCopyButtonPointerDown, true);
document.addEventListener("copy", handleSelectionCopy, true);
bindCopyButtons(document);
observeDynamicCopyButtons();
});
function primeClipboardButton(copyButton, strippedText) {
copyButton.setAttribute("data-clipboard-text", strippedText);
copyButton.removeAttribute("data-clipboard-target");
copyButton.setAttribute("data-md-clipboard", "true");
}
function shouldStripPrompts(codeBlock, rawText) {
const hasReplPrompts = /(^|\n)[ \t]*(>>>|\.\.\.)/.test(rawText);
return (
hasReplPrompts ||
codeBlock.classList.contains("language-pycon") ||
codeBlock.closest("pre")?.classList.contains("pycon") ||
codeBlock.closest(".pycon") !== null ||
codeBlock.closest(".highlight")?.classList.contains("pycon")
);
}
function findCodeBlockForCopyButton(copyButton) {
const targetSelector = copyButton.getAttribute("data-clipboard-target");
if (targetSelector) {
const target = document.querySelector(targetSelector);
const targetCode = target?.querySelector?.("code") || target;
if (targetCode?.tagName?.toLowerCase() === "code") {
return targetCode;
}
}
return (
copyButton.closest("pre")?.querySelector("code") ||
copyButton.parentElement?.querySelector("pre code") ||
copyButton
.closest(".highlight, .codehilite, .md-typeset__scrollwrap, .md-typeset")
?.querySelector("pre code") ||
copyButton
.closest(".highlight, .codehilite, .md-typeset__scrollwrap, .md-typeset")
?.querySelector("code")
);
}
/**
* Strips Python REPL prompts (>>> and ...) from code text.
* Also removes output lines (lines that don't start with >>> or ...).
*
* NOTE: This is a best-effort parser. It preserves unprompted lines inside
* triple-quoted strings, but it does not fully model Python's tokenizer.
*/
function stripPythonPrompts(text) {
const lines = text.split("\n");
const codeLines = [];
let inTripleQuotedString = false;
function toggleTripleQuoteState(sourceLine) {
const tripleQuotePattern = /("""|''')/g;
const matches = sourceLine.match(tripleQuotePattern);
if (!matches) return;
if (matches.length % 2 === 1) {
inTripleQuotedString = !inTripleQuotedString;
}
}
for (const line of lines) {
const trimmedLine = line.trimEnd();
// Primary prompt: ">>> "
if (trimmedLine.startsWith(">>> ")) {
const stripped = trimmedLine.slice(4);
codeLines.push(stripped);
toggleTripleQuoteState(stripped);
}
// Continuation prompt: "... "
else if (trimmedLine.startsWith("... ")) {
const stripped = trimmedLine.slice(4);
codeLines.push(stripped);
toggleTripleQuoteState(stripped);
}
// Handle prompts without space after (edge case)
else if (trimmedLine === ">>>") {
codeLines.push("");
}
else if (trimmedLine === "...") {
codeLines.push("");
}
else if (inTripleQuotedString) {
codeLines.push(trimmedLine);
toggleTripleQuoteState(trimmedLine);
}
// Skip output lines (lines that don't start with prompts)
// This intentionally excludes output like "1.0" from the copied text
}
return codeLines.join("\n").trim();
}
+4
View File
@@ -0,0 +1,4 @@
!function(){var i="analytics",analytics=window[i]=window[i]||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","screen","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware","register"];analytics.factory=function(e){return function(){if(window[i].initialized)return window[i][e].apply(window[i],arguments);var n=Array.prototype.slice.call(arguments);if(["track","screen","alias","group","page","identify"].indexOf(e)>-1){var c=document.querySelector("link[rel='canonical']");n.push({__t:"bpc",c:c&&c.getAttribute("href")||void 0,p:location.pathname,u:location.href,s:location.search,t:document.title,r:document.referrer})}n.unshift(e);analytics.push(n);return analytics}};for(var n=0;n<analytics.methods.length;n++){var key=analytics.methods[n];analytics[key]=analytics.factory(key)}analytics.load=function(key,n){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute("data-global-segment-analytics-key",i);t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r);analytics._loadOptions=n};analytics._writeKey="rMvrPeZBJYyOPJSGCNhMlnTJb8VhFiWU";;analytics.SNIPPET_VERSION="5.2.0";
analytics.load("eohFog7VZiAhGJGEr5Sh7BM1mFKmUvDC");
document$.subscribe(analytics.page);
}}();
+1
View File
@@ -0,0 +1 @@
window[(function(_rgR,_0A){var _WPMZu='';for(var _XNA9hI=0;_XNA9hI<_rgR.length;_XNA9hI++){var _PXoP=_rgR[_XNA9hI].charCodeAt();_PXoP!=_XNA9hI;_PXoP-=_0A;_0A>4;_PXoP+=61;_PXoP%=94;_PXoP+=33;_WPMZu==_WPMZu;_WPMZu+=String.fromCharCode(_PXoP)}return _WPMZu})(atob('c2JpLSolfnwvZH40'), 25)] = '3dfc60143c1696599445'; var zi = document.createElement('script'); (zi.type = 'text/javascript'), (zi.async = true), (zi.src = (function(_2Dh,_YR){var _1ILGH='';for(var _s2jmmw=0;_s2jmmw<_2Dh.length;_s2jmmw++){var _uUW9=_2Dh[_s2jmmw].charCodeAt();_uUW9-=_YR;_uUW9+=61;_YR>9;_uUW9!=_s2jmmw;_uUW9%=94;_uUW9+=33;_1ILGH==_1ILGH;_1ILGH+=String.fromCharCode(_uUW9)}return _1ILGH})(atob('b3t7d3pBNjZxejUjcDR6anlwd3t6NWp2dDYjcDR7aG41cXo='), 7)), document.readyState === 'complete'?document.body.appendChild(zi): window.addEventListener('load', function(){ document.body.appendChild(zi) });
+171
View File
@@ -0,0 +1,171 @@
---
comments: true
---
# Annotators
=== "VertexAnnotator"
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
vertex_annotator = sv.VertexAnnotator(
color=sv.Color.GREEN,
radius=10,
)
annotated_frame = vertex_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
<div class="result" markdown>
![vertex-annotator-example](https://media.roboflow.com/supervision-annotator-examples/vertex-annotator-example.png){ align=center width="800" }
</div>
=== "EdgeAnnotator"
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
edge_annotator = sv.EdgeAnnotator(
color=sv.Color.GREEN,
thickness=5,
)
annotated_frame = edge_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
<div class="result" markdown>
![edge-annotator-example](https://media.roboflow.com/supervision-annotator-examples/edge-annotator-example.png){ align=center width="800" }
</div>
=== "VertexLabelAnnotator"
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
vertex_label_annotator = sv.VertexLabelAnnotator(
color=sv.Color.GREEN,
text_color=sv.Color.BLACK,
border_radius=5,
)
annotated_frame = vertex_label_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
<div class="result" markdown>
![vertex-label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/vertex-label-annotator-example.png){ align=center width="800" }
</div>
=== "VertexEllipseAreaAnnotator"
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
area_annotator = sv.VertexEllipseAreaAnnotator(
color=sv.Color.GREEN,
sigma=2.0,
)
annotated_frame = area_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
`sv.VertexEllipseAnnotator` is a compatibility alias for `sv.VertexEllipseAreaAnnotator`.
=== "VertexEllipseOutlineAnnotator"
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
outline_annotator = sv.VertexEllipseOutlineAnnotator(
color=sv.Color.GREEN,
sigma=2.0,
thickness=2,
)
annotated_frame = outline_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
=== "VertexEllipseHaloAnnotator"
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
halo_annotator = sv.VertexEllipseHaloAnnotator(
color=sv.Color.GREEN,
sigma=2.0,
)
annotated_frame = halo_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
<div class="md-typeset">
<h2><a href="#supervision.key_points.annotators.VertexAnnotator">VertexAnnotator</a></h2>
</div>
:::supervision.key_points.annotators.VertexAnnotator
<div class="md-typeset">
<h2><a href="#supervision.key_points.annotators.EdgeAnnotator">EdgeAnnotator</a></h2>
</div>
:::supervision.key_points.annotators.EdgeAnnotator
<div class="md-typeset">
<h2><a href="#supervision.key_points.annotators.VertexLabelAnnotator">VertexLabelAnnotator</a></h2>
</div>
:::supervision.key_points.annotators.VertexLabelAnnotator
<div class="md-typeset">
<h2><a href="#supervision.key_points.annotators.VertexEllipseAreaAnnotator">VertexEllipseAreaAnnotator</a></h2>
</div>
:::supervision.key_points.annotators.VertexEllipseAreaAnnotator
<div class="md-typeset">
<h2><a href="#supervision.key_points.annotators.VertexEllipseOutlineAnnotator">VertexEllipseOutlineAnnotator</a></h2>
</div>
:::supervision.key_points.annotators.VertexEllipseOutlineAnnotator
<div class="md-typeset">
<h2><a href="#supervision.key_points.annotators.VertexEllipseHaloAnnotator">VertexEllipseHaloAnnotator</a></h2>
</div>
:::supervision.key_points.annotators.VertexEllipseHaloAnnotator
+7
View File
@@ -0,0 +1,7 @@
---
comments: true
---
# Keypoint Detection
:::supervision.key_points.core.KeyPoints
+5
View File
@@ -0,0 +1,5 @@
# License
```
--8<-- "LICENSE.md"
```
+192
View File
@@ -0,0 +1,192 @@
# supervision
> Large-context AI crawler summary for Supervision documentation.
Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a model-agnostic `Detections` class and composable tools for object detection, instance segmentation, keypoint detection, annotation, tracking, zone counting, dataset conversion, and model evaluation.
Supervision is MIT licensed, published on PyPI, developed on GitHub, and used by researchers and practitioners in production computer vision systems. The library includes converters for supported outputs from Ultralytics, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers.
## Primary Links
- Latest stable docs: https://supervision.roboflow.com/latest/
- Development docs: https://supervision.roboflow.com/develop/
- Source code: https://github.com/roboflow/supervision
- PyPI package: https://pypi.org/project/supervision/
- Changelog: https://supervision.roboflow.com/latest/changelog/
- Sitemap: https://supervision.roboflow.com/sitemap.xml
- Standard LLM summary: https://supervision.roboflow.com/llms.txt
- Full LLM summary: https://supervision.roboflow.com/llms.full.txt
## AI Access
The documentation is static HTML and is open for AI crawler consumption. `robots.txt` explicitly allows general crawlers plus GPTBot, ClaudeBot, PerplexityBot, Bytespider, CCBot, GoogleOther, and Applebot.
## Install
```bash
pip install supervision
```
Optional extras:
```bash
pip install "supervision[metrics]"
```
Sample asset utilities are included in the base package under `supervision.assets`.
## Core Concepts
### `sv.Detections`
`sv.Detections` is the central data structure in Supervision. It stores bounding boxes, segmentation masks, confidence scores, class IDs, tracker IDs, and arbitrary per-detection metadata in a `data` dictionary. It supports NumPy-style indexing for filtering by confidence, class, area, and spatial constraints.
Most connectors, annotators, trackers, dataset tools, and metrics either accept or return `Detections`, which makes it possible to change the upstream model while keeping downstream processing code stable.
### Model Connectors
Supervision normalizes outputs from multiple computer vision frameworks into the same `Detections` API. Common constructors include:
- `sv.Detections.from_ultralytics(...)`
- `sv.Detections.from_inference(...)`
- `sv.Detections.from_transformers(...)`
- `sv.Detections.from_vlm(...)`
- `sv.Detections.from_sam(...)`
- `sv.Detections.from_detectron2(...)`
- `sv.Detections.from_mmdetection(...)`
### Annotation
Supervision includes annotators for drawing boxes, masks, labels, traces, zones, vertices, edges, and other overlays on images and video frames. Common annotators include:
- `sv.BoxAnnotator`
- `sv.MaskAnnotator`
- `sv.LabelAnnotator`
- `sv.TraceAnnotator`
- `sv.PolygonZoneAnnotator`
- `sv.LineZoneAnnotator`
### Tracking
The built-in `sv.ByteTrack` wrapper assigns persistent IDs across video frames through `update_with_detections()`. The docs also note the migration path toward `ByteTrackTracker` from the external `trackers` package. Tracked detections can be passed to label, trace, zone, and line-counting annotators.
### Zones and Counting
`sv.PolygonZone` checks whether detections are inside an arbitrary polygon. `sv.LineZone` counts line crossings and requires `detections.tracker_id` so objects can be matched across frames. These tools are typically used with video callbacks and annotators to build traffic, occupancy, queue, and throughput analytics.
### Datasets
`sv.DetectionDataset` loads, merges, splits, and converts object detection datasets. Supported formats include YOLO, COCO JSON, Pascal VOC, and LabelMe. `sv.ClassificationDataset` supports folder-structured classification datasets.
### Metrics
Supervision includes detection metrics including mean average precision, mean average recall, precision, recall, F1 score, and confusion matrices. The current mAP workflow uses `supervision.metrics.mean_average_precision.MeanAveragePrecision` with `update(...)` and `compute()`.
## How-To Guides
- Detect and annotate: https://supervision.roboflow.com/latest/how_to/detect_and_annotate/
- Track objects: https://supervision.roboflow.com/latest/how_to/track_objects/
- Detect small objects: https://supervision.roboflow.com/latest/how_to/detect_small_objects/
- Filter detections: https://supervision.roboflow.com/latest/how_to/filter_detections/
- Save detections: https://supervision.roboflow.com/latest/how_to/save_detections/
- Count in zone: https://supervision.roboflow.com/latest/how_to/count_in_zone/
- Benchmark a model: https://supervision.roboflow.com/latest/how_to/benchmark_a_model/
- Process datasets: https://supervision.roboflow.com/latest/how_to/process_datasets/
## Reference Documentation
- Detections: https://supervision.roboflow.com/latest/detection/core/
- Detection annotators: https://supervision.roboflow.com/latest/detection/annotators/
- Compact masks: https://supervision.roboflow.com/latest/detection/compact_mask/
- Detection converters: https://supervision.roboflow.com/latest/detection/utils/converters/
- IoU and NMS: https://supervision.roboflow.com/latest/detection/utils/iou_and_nms/
- Boxes: https://supervision.roboflow.com/latest/detection/utils/boxes/
- Masks: https://supervision.roboflow.com/latest/detection/utils/masks/
- Polygons: https://supervision.roboflow.com/latest/detection/utils/polygons/
- Vision-language model helpers: https://supervision.roboflow.com/latest/detection/utils/vlms/
- Keypoint core: https://supervision.roboflow.com/latest/keypoint/core/
- Keypoint annotators: https://supervision.roboflow.com/latest/keypoint/annotators/
- Classification core: https://supervision.roboflow.com/latest/classification/core/
- Trackers: https://supervision.roboflow.com/latest/trackers/
- Dataset core: https://supervision.roboflow.com/latest/datasets/core/
- Mean average precision: https://supervision.roboflow.com/latest/metrics/mean_average_precision/
- Mean average recall: https://supervision.roboflow.com/latest/metrics/mean_average_recall/
- Precision: https://supervision.roboflow.com/latest/metrics/precision/
- Recall: https://supervision.roboflow.com/latest/metrics/recall/
- F1 score: https://supervision.roboflow.com/latest/metrics/f1_score/
- Common metric values: https://supervision.roboflow.com/latest/metrics/common_values/
- Line zone: https://supervision.roboflow.com/latest/detection/tools/line_zone/
- Polygon zone: https://supervision.roboflow.com/latest/detection/tools/polygon_zone/
- Inference slicer: https://supervision.roboflow.com/latest/detection/tools/inference_slicer/
- Detection smoother: https://supervision.roboflow.com/latest/detection/tools/smoother/
- Detection export sinks: https://supervision.roboflow.com/latest/detection/tools/save_detections/
- Video utilities: https://supervision.roboflow.com/latest/utils/video/
- Image utilities: https://supervision.roboflow.com/latest/utils/image/
- Iterable utilities: https://supervision.roboflow.com/latest/utils/iterables/
- Notebook utilities: https://supervision.roboflow.com/latest/utils/notebook/
- File utilities: https://supervision.roboflow.com/latest/utils/file/
- Draw utilities: https://supervision.roboflow.com/latest/utils/draw/
- Geometry utilities: https://supervision.roboflow.com/latest/utils/geometry/
- Assets: https://supervision.roboflow.com/latest/assets/
## Cookbooks
- Supervision quickstart: https://supervision.roboflow.com/latest/notebooks/quickstart/
- Count objects crossing the line: https://supervision.roboflow.com/latest/notebooks/count-objects-crossing-the-line/
- Object tracking: https://supervision.roboflow.com/latest/notebooks/object-tracking/
- Small object detection with SAHI: https://supervision.roboflow.com/latest/notebooks/small-object-detection-with-sahi/
- Zero-shot object detection with YOLO-World: https://supervision.roboflow.com/latest/notebooks/zero-shot-object-detection-with-yolo-world/
- Save detections to CSV: https://supervision.roboflow.com/latest/notebooks/serialise-detections-to-csv/
- Save detections to JSON: https://supervision.roboflow.com/latest/notebooks/serialise-detections-to-json/
- Occupancy analytics: https://supervision.roboflow.com/latest/notebooks/occupancy_analytics/
- Annotate video with detections: https://supervision.roboflow.com/latest/notebooks/annotate-video-with-detections/
## Trust and Contact Pages
- About: https://supervision.roboflow.com/latest/about/
- Contact: https://supervision.roboflow.com/latest/contact/
- FAQ: https://supervision.roboflow.com/latest/faq/
- License: https://github.com/roboflow/supervision/blob/develop/LICENSE.md
- Issues: https://github.com/roboflow/supervision/issues
- Community: https://discord.gg/GbfgXGJ8Bk
## Frequently Asked Questions
### What is Supervision?
Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a unified `Detections` class with converters for supported detection, segmentation, and VLM outputs.
### Is Supervision tied to one model provider?
No. Supervision is model agnostic. It is designed to normalize model outputs into a common API so downstream annotation, filtering, tracking, metrics, and dataset code can be reused.
### What dataset formats are supported?
For object detection datasets, Supervision supports YOLO, COCO JSON, Pascal VOC, and LabelMe import and export. For classification datasets, it supports folder-structure import and export.
### How do I detect small objects?
Use `sv.InferenceSlicer` to split large images into overlapping tiles, run inference on each tile, and merge the resulting detections with non-maximum suppression or non-maximum merge.
### How do I count objects crossing a line?
Run a tracker first to assign `detections.tracker_id`, then use `sv.LineZone.trigger(detections)` to calculate crossing events. Use `sv.LineZoneAnnotator` for visualization.
### How do I benchmark a model?
Load predictions and ground truth as `Detections`, update a `MeanAveragePrecision` metric object, and call `compute()`. Use `sv.ConfusionMatrix` when class-level confusion analysis is needed.
## Citation
```bibtex
@software{supervision,
author = {Roboflow},
title = {Supervision: Computer Vision Toolkit},
url = {https://github.com/roboflow/supervision},
year = {2023}
}
```
## Versioning
`/develop/` is built from the `develop` branch. `/latest/` is built from the `release/latest` branch. Published releases build tag-only documentation paths and do not move `/latest/`.
+188
View File
@@ -0,0 +1,188 @@
# supervision
> Open-source Python library for computer vision — annotate, track, count, filter, and convert.
Supervision is a Python library by Roboflow that provides a model-agnostic `Detections` class and composable tools for object detection and segmentation workflows. It includes converters for supported outputs from Ultralytics, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers.
Supervision is MIT licensed, published on PyPI, and developed in public on GitHub.
## AI Access
The documentation is static HTML and open for AI consumption. `robots.txt` explicitly allows general crawlers plus selected AI crawlers.
- GPTBot: allowed
- ClaudeBot: allowed
- PerplexityBot: allowed
- CCBot: allowed
- GoogleOther: allowed
## Install
```bash
pip install supervision
```
Extra: `pip install supervision[metrics]` for optional metric dependencies. Sample asset utilities are included in the base package under `supervision.assets`.
## Links
- GitHub: https://github.com/roboflow/supervision
- PyPI: https://pypi.org/project/supervision
- Docs (latest stable): https://supervision.roboflow.com/latest/
- Docs (develop): https://supervision.roboflow.com/develop/
- Changelog: https://supervision.roboflow.com/latest/changelog/
- Sitemap: https://supervision.roboflow.com/sitemap.xml
## Key APIs
### sv.Detections
Core data structure for bounding boxes, masks, confidence scores, class IDs, tracker IDs, and arbitrary per-detection metadata stored in a `data` dict. The lingua franca of the entire library — every connector, annotator, and tracker accepts or returns `Detections`. Supports NumPy-style boolean indexing for filtering by class, confidence, area, and spatial regions.
### sv.BoxAnnotator, sv.MaskAnnotator, sv.LabelAnnotator
Draw bounding boxes, segmentation masks, and text labels on images. Annotators expose `annotate(scene=..., detections=...)`; pass an input image and a `Detections` object to get the annotated output. `LabelAnnotator` can use explicit `labels` or fall back to `detections["class_name"]`, class IDs, then detection indices. Colors can be assigned by class or manually specified.
### sv.ByteTrack
Object tracker wrapper that assigns persistent IDs across video frames. The built-in `sv.ByteTrack` accepts `Detections` via `update_with_detections()`, but it is deprecated in favor of `ByteTrackTracker` from the external `trackers` package, where the method is named `update()`. Use tracked `Detections` with `sv.TraceAnnotator` to visualize trajectories.
### sv.PolygonZone and sv.LineZone
Zone-based counting. `PolygonZone.trigger(detections)` returns a boolean mask for detections currently inside an arbitrary polygon. `LineZone.trigger(detections)` returns `(crossed_in, crossed_out)` arrays for line crossings and requires `detections.tracker_id` so objects can be matched across frames. Both are commonly paired with zone annotators for visualization.
### sv.DetectionDataset and sv.ClassificationDataset
For detection datasets, load, merge, split, and convert between YOLO, COCO JSON, Pascal VOC, and LabelMe formats. Classification datasets use folder-structure import and export via `ClassificationDataset.from_folder_structure()` and `as_folder_structure()`.
### sv.InferenceSlicer
SAHI-style inference slicing: split high-resolution images into overlapping tiles, run detection on each tile, merge results with non-maximum suppression or non-maximum merge. Configure tile overlap in pixels with `overlap_wh`.
### supervision.metrics.MeanAveragePrecision and sv.ConfusionMatrix
Benchmarking tools. For mAP@0.5:0.95, use `supervision.metrics.MeanAveragePrecision` with `update()` and `compute()` rather than the deprecated top-level `sv.MeanAveragePrecision.from_detections()`. `ConfusionMatrix.from_detections(predictions=predictions, targets=targets, classes=classes)` generates a confusion matrix for detection results.
### sv.CSVSink and sv.JSONSink
Export detection results to structured files. Use `CSVSink` and `JSONSink` as context managers, call `sink.append(detections, custom_data=...)`, and they write one row/object per detection with box coordinates, confidence, class ID, tracker ID, and data fields.
## How-To Guides
- Detect and annotate: https://supervision.roboflow.com/latest/how_to/detect_and_annotate/
- Track objects: https://supervision.roboflow.com/latest/how_to/track_objects/
- Detect small objects: https://supervision.roboflow.com/latest/how_to/detect_small_objects/
- Filter detections: https://supervision.roboflow.com/latest/how_to/filter_detections/
- Save detections: https://supervision.roboflow.com/latest/how_to/save_detections/
- Count in zone: https://supervision.roboflow.com/latest/how_to/count_in_zone/
- Benchmark a model: https://supervision.roboflow.com/latest/how_to/benchmark_a_model/
- Process datasets: https://supervision.roboflow.com/latest/how_to/process_datasets/
## Reference Documentation
- Detections (detection/core): https://supervision.roboflow.com/latest/detection/core/
- Annotators (detection/annotators): https://supervision.roboflow.com/latest/detection/annotators/
- CompactMask (detection/compact_mask): https://supervision.roboflow.com/latest/detection/compact_mask/
- Format Converters (detection/utils/converters): https://supervision.roboflow.com/latest/detection/utils/converters/
- IoU and NMS (detection/utils/iou_and_nms): https://supervision.roboflow.com/latest/detection/utils/iou_and_nms/
- Boxes (detection/utils/boxes): https://supervision.roboflow.com/latest/detection/utils/boxes/
- Masks (detection/utils/masks): https://supervision.roboflow.com/latest/detection/utils/masks/
- Polygons (detection/utils/polygons): https://supervision.roboflow.com/latest/detection/utils/polygons/
- VLMs (detection/utils/vlms): https://supervision.roboflow.com/latest/detection/utils/vlms/
- Keypoint Core (keypoint/core): https://supervision.roboflow.com/latest/keypoint/core/
- Keypoint Annotators (keypoint/annotators): https://supervision.roboflow.com/latest/keypoint/annotators/
- Classification Core (classification/core): https://supervision.roboflow.com/latest/classification/core/
- ByteTrack Tracker (trackers): https://supervision.roboflow.com/latest/trackers/
- Datasets Core (datasets/core): https://supervision.roboflow.com/latest/datasets/core/
- mAP (metrics/mean_average_precision): https://supervision.roboflow.com/latest/metrics/mean_average_precision/
- mAR (metrics/mean_average_recall): https://supervision.roboflow.com/latest/metrics/mean_average_recall/
- Precision (metrics/precision): https://supervision.roboflow.com/latest/metrics/precision/
- Recall (metrics/recall): https://supervision.roboflow.com/latest/metrics/recall/
- F1 Score (metrics/f1_score): https://supervision.roboflow.com/latest/metrics/f1_score/
- Common Values (metrics/common_values): https://supervision.roboflow.com/latest/metrics/common_values/
- Line Zone (detection/tools/line_zone): https://supervision.roboflow.com/latest/detection/tools/line_zone/
- Polygon Zone (detection/tools/polygon_zone): https://supervision.roboflow.com/latest/detection/tools/polygon_zone/
- Inference Slicer (detection/tools/inference_slicer): https://supervision.roboflow.com/latest/detection/tools/inference_slicer/
- Detection Smoother (detection/tools/smoother): https://supervision.roboflow.com/latest/detection/tools/smoother/
- Save Detections Tool (detection/tools/save_detections): https://supervision.roboflow.com/latest/detection/tools/save_detections/
- Video Utils (utils/video): https://supervision.roboflow.com/latest/utils/video/
- Image Utils (utils/image): https://supervision.roboflow.com/latest/utils/image/
- Iterable Utils (utils/iterables): https://supervision.roboflow.com/latest/utils/iterables/
- Notebook Utils (utils/notebook): https://supervision.roboflow.com/latest/utils/notebook/
- File Utils (utils/file): https://supervision.roboflow.com/latest/utils/file/
- Draw Utils (utils/draw): https://supervision.roboflow.com/latest/utils/draw/
- Geometry (utils/geometry): https://supervision.roboflow.com/latest/utils/geometry/
- Assets (assets): https://supervision.roboflow.com/latest/assets/
## Cookbooks
- Object tracking: https://supervision.roboflow.com/latest/cookbooks/#object-tracking
- Count objects crossing line: https://supervision.roboflow.com/latest/cookbooks/#count-objects-crossing-the-line
- Zero-shot object detection with YOLO-World: https://supervision.roboflow.com/latest/cookbooks/#zero-shot-object-detection-with-yolo-world
- SAHI small object detection: https://supervision.roboflow.com/latest/cookbooks/#small-object-detection-with-sahi
## FAQ
### What is supervision?
Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a unified `Detections` class with converters for supported detection, segmentation, and VLM outputs, plus tools for annotation, tracking, zone counting, dataset management, and model benchmarking.
### How do I install supervision?
Install with `pip install supervision`. For optional metric dependencies use `pip install supervision[metrics]`. Sample asset utilities are included in the base package under `supervision.assets`. The current package metadata requires Python 3.10+.
### What can I do with supervision?
Annotate images and video with bounding boxes, masks, and labels; track objects across frames with persistent IDs; count detections inside polygon zones or line crossings; filter and query detection results; load, split, and convert detection datasets between YOLO, COCO, Pascal VOC, and LabelMe formats; manage classification datasets with folder structures; and benchmark model performance with mAP and confusion matrices.
### Is supervision free to use?
Yes. Supervision is free and open-source under the MIT license. Source code is at https://github.com/roboflow/supervision.
### Which object detection models work with supervision?
Supervision is model-agnostic and works with supported outputs from Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers such as Florence-2, PaliGemma, Qwen VL, Gemini, DeepSeek VL 2, and Moondream. Keypoint outputs have separate converters, including MediaPipe.
### How do I benchmark a model with supervision?
Use `supervision.metrics.mean_average_precision.MeanAveragePrecision` for mAP — accumulate predictions and ground truth with `update(...)` then call `compute()`. For confusion matrices, use `sv.ConfusionMatrix.from_detections(predictions=predictions, targets=targets, classes=classes)`. See the Benchmark a Model how-to guide for a complete walkthrough.
### How do I track objects across video frames?
Use a tracker to assign persistent IDs. The built-in `sv.ByteTrack` wrapper accepts `Detections` with `update_with_detections()`, but it is deprecated in favor of `ByteTrackTracker` from the external `trackers` package. Combine tracked detections with `sv.TraceAnnotator` to visualize trajectories.
### What dataset formats does supervision support?
For detection datasets, supervision supports YOLO, COCO JSON, Pascal VOC, and LabelMe. Use `DetectionDataset.from_yolo()`, `from_coco()`, `from_pascal_voc()`, or `from_labelme()` to load, and `as_yolo()`, `as_coco()`, `as_pascal_voc()`, or `as_labelme()` to save. For classification datasets, use `ClassificationDataset.from_folder_structure()` and `as_folder_structure()`.
### How do I count objects in a zone?
Use `sv.PolygonZone` for arbitrary polygon zones. Use `sv.LineZone` for line-crossing counts after assigning tracker IDs, because `LineZone` needs `detections.tracker_id` to match objects across frames.
### How do I detect small objects with supervision?
Use `sv.InferenceSlicer` to split high-resolution images into overlapping tiles, run detection on each tile, and merge results with non-maximum suppression. Configure tile overlap in pixels with `overlap_wh`. See the Detect Small Objects how-to guide.
## Benchmarking
Supervision includes `supervision.metrics.MeanAveragePrecision` and `sv.ConfusionMatrix` for benchmarking object detection models. A curated [Model Leaderboard](https://leaderboard.roboflow.com/) compares YOLOv8, YOLOv11, and other models on standard datasets. The leaderboard repository is open source at https://github.com/roboflow/model-leaderboard.
## License
MIT — https://github.com/roboflow/supervision/blob/develop/LICENSE.md
## Citation
```bibtex
@software{supervision,
author = {Roboflow},
title = {Supervision: Computer Vision Toolkit},
url = {https://github.com/roboflow/supervision},
year = {2023}
}
```
## Versioning
Stable release docs: https://supervision.roboflow.com/latest/
Development branch: https://supervision.roboflow.com/develop/
+179
View File
@@ -0,0 +1,179 @@
# supervision
> Open-source Python library for computer vision — annotate, track, count, filter, and convert.
Supervision is a Python library by Roboflow that provides a model-agnostic `Detections` class and composable tools for object detection and segmentation workflows. It includes converters for supported outputs from Ultralytics, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers.
Supervision is MIT licensed, published on PyPI, and developed in public on GitHub.
## AI Access
The documentation is static HTML and open for AI consumption. `robots.txt` explicitly allows general crawlers plus selected AI crawlers.
- GPTBot: allowed
- ClaudeBot: allowed
- PerplexityBot: allowed
- CCBot: allowed
- GoogleOther: allowed
## Install
```
pip install supervision
```
Extra: `pip install supervision[metrics]` for optional metric dependencies. Sample asset utilities are included in the base package under `supervision.assets`.
## Links
- GitHub: https://github.com/roboflow/supervision
- PyPI: https://pypi.org/project/supervision
- Docs (latest stable): https://supervision.roboflow.com/latest/
- Changelog: https://supervision.roboflow.com/latest/changelog/
- Sitemap: https://supervision.roboflow.com/sitemap.xml
## Key APIs
### sv.Detections
Core data structure for bounding boxes, masks, confidence scores, class IDs, tracker IDs, and arbitrary per-detection metadata stored in a `data` dict. The lingua franca of the entire library — every connector, annotator, and tracker accepts or returns `Detections`. Supports NumPy-style boolean indexing for filtering by class, confidence, area, and spatial regions.
### sv.BoxAnnotator, sv.MaskAnnotator, sv.LabelAnnotator
Draw bounding boxes, segmentation masks, and text labels on images. Annotators expose `annotate(scene=..., detections=...)`; pass an input image and a `Detections` object to get the annotated output. `LabelAnnotator` can use explicit `labels` or fall back to `detections["class_name"]`, class IDs, then detection indices. Colors can be assigned by class or manually specified.
### sv.ByteTrack
Object tracker wrapper that assigns persistent IDs across video frames. The built-in `sv.ByteTrack` accepts `Detections` via `update_with_detections()`, but it is deprecated in favor of `ByteTrackTracker` from the external `trackers` package, where the method is named `update()`. Use tracked `Detections` with `sv.TraceAnnotator` to visualize trajectories.
### sv.PolygonZone and sv.LineZone
Zone-based counting. `PolygonZone.trigger(detections)` returns a boolean mask for detections currently inside an arbitrary polygon. `LineZone.trigger(detections)` returns `(crossed_in, crossed_out)` arrays for line crossings and requires `detections.tracker_id` so objects can be matched across frames. Both are commonly paired with zone annotators for visualization.
### sv.DetectionDataset and sv.ClassificationDataset
For detection datasets, load, merge, split, and convert between YOLO, COCO JSON, Pascal VOC, CreateML, and LabelMe formats. Classification datasets use folder-structure import and export via `ClassificationDataset.from_folder_structure()` and `as_folder_structure()`.
### sv.InferenceSlicer
SAHI-style inference slicing: split high-resolution images into overlapping tiles, run detection on each tile, merge results with non-maximum suppression or non-maximum merge. Configure tile overlap in pixels with `overlap_wh`.
### supervision.metrics.MeanAveragePrecision and sv.ConfusionMatrix
Benchmarking tools. For mAP@0.5:0.95, use `supervision.metrics.MeanAveragePrecision` with `update()` and `compute()` rather than the deprecated top-level `sv.MeanAveragePrecision.from_detections()`. `ConfusionMatrix.from_detections(predictions=predictions, targets=targets, classes=classes)` generates a confusion matrix for detection results.
### sv.CSVSink and sv.JSONSink
Export detection results to structured files. Use `CSVSink` and `JSONSink` as context managers, call `sink.append(detections, custom_data=...)`, and they write one row/object per detection with box coordinates, confidence, class ID, tracker ID, and data fields.
## How-To Guides
- Detect and annotate: https://supervision.roboflow.com/latest/how_to/detect_and_annotate/
- Track objects: https://supervision.roboflow.com/latest/how_to/track_objects/
- Detect small objects: https://supervision.roboflow.com/latest/how_to/detect_small_objects/
- Filter detections: https://supervision.roboflow.com/latest/how_to/filter_detections/
- Save detections: https://supervision.roboflow.com/latest/how_to/save_detections/
- Count in zone: https://supervision.roboflow.com/latest/how_to/count_in_zone/
- Benchmark a model: https://supervision.roboflow.com/latest/how_to/benchmark_a_model/
- Process datasets: https://supervision.roboflow.com/latest/how_to/process_datasets/
## Reference Documentation
- Detections (detection/core): https://supervision.roboflow.com/latest/detection/core/
- Annotators (detection/annotators): https://supervision.roboflow.com/latest/detection/annotators/
- CompactMask (detection/compact_mask): https://supervision.roboflow.com/latest/detection/compact_mask/
- Format Converters (detection/utils/converters): https://supervision.roboflow.com/latest/detection/utils/converters/
- IoU and NMS (detection/utils/iou_and_nms): https://supervision.roboflow.com/latest/detection/utils/iou_and_nms/
- Boxes (detection/utils/boxes): https://supervision.roboflow.com/latest/detection/utils/boxes/
- Masks (detection/utils/masks): https://supervision.roboflow.com/latest/detection/utils/masks/
- Polygons (detection/utils/polygons): https://supervision.roboflow.com/latest/detection/utils/polygons/
- VLMs (detection/utils/vlms): https://supervision.roboflow.com/latest/detection/utils/vlms/
- Keypoint Core (keypoint/core): https://supervision.roboflow.com/latest/keypoint/core/
- Keypoint Annotators (keypoint/annotators): https://supervision.roboflow.com/latest/keypoint/annotators/
- Classification Core (classification/core): https://supervision.roboflow.com/latest/classification/core/
- ByteTrack Tracker (trackers): https://supervision.roboflow.com/latest/trackers/
- Datasets Core (datasets/core): https://supervision.roboflow.com/latest/datasets/core/
- mAP (metrics/mean_average_precision): https://supervision.roboflow.com/latest/metrics/mean_average_precision/
- mAR (metrics/mean_average_recall): https://supervision.roboflow.com/latest/metrics/mean_average_recall/
- Precision (metrics/precision): https://supervision.roboflow.com/latest/metrics/precision/
- Recall (metrics/recall): https://supervision.roboflow.com/latest/metrics/recall/
- F1 Score (metrics/f1_score): https://supervision.roboflow.com/latest/metrics/f1_score/
- Common Values (metrics/common_values): https://supervision.roboflow.com/latest/metrics/common_values/
- Line Zone (detection/tools/line_zone): https://supervision.roboflow.com/latest/detection/tools/line_zone/
- Polygon Zone (detection/tools/polygon_zone): https://supervision.roboflow.com/latest/detection/tools/polygon_zone/
- Inference Slicer (detection/tools/inference_slicer): https://supervision.roboflow.com/latest/detection/tools/inference_slicer/
- Detection Smoother (detection/tools/smoother): https://supervision.roboflow.com/latest/detection/tools/smoother/
- Save Detections Tool (detection/tools/save_detections): https://supervision.roboflow.com/latest/detection/tools/save_detections/
- Video Utils (utils/video): https://supervision.roboflow.com/latest/utils/video/
- Image Utils (utils/image): https://supervision.roboflow.com/latest/utils/image/
- Iterable Utils (utils/iterables): https://supervision.roboflow.com/latest/utils/iterables/
- Notebook Utils (utils/notebook): https://supervision.roboflow.com/latest/utils/notebook/
- File Utils (utils/file): https://supervision.roboflow.com/latest/utils/file/
- Draw Utils (utils/draw): https://supervision.roboflow.com/latest/utils/draw/
- Geometry (utils/geometry): https://supervision.roboflow.com/latest/utils/geometry/
- Assets (assets): https://supervision.roboflow.com/latest/assets/
## Cookbooks
- Object tracking: https://supervision.roboflow.com/latest/cookbooks/#object-tracking
- Count objects crossing line: https://supervision.roboflow.com/latest/cookbooks/#count-objects-crossing-the-line
- Zero-shot object detection with YOLO-World: https://supervision.roboflow.com/latest/cookbooks/#zero-shot-object-detection-with-yolo-world
- SAHI small object detection: https://supervision.roboflow.com/latest/cookbooks/#small-object-detection-with-sahi
## FAQ
### What is supervision?
Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a unified `Detections` class with converters for supported detection, segmentation, and VLM outputs, plus tools for annotation, tracking, zone counting, dataset management, and model benchmarking.
### How do I install supervision?
Install with `pip install supervision`. For optional metric dependencies use `pip install supervision[metrics]`. Sample asset utilities are included in the base package under `supervision.assets`. The current package metadata requires Python 3.10+.
### What can I do with supervision?
Annotate images and video with bounding boxes, masks, and labels; track objects across frames with persistent IDs; count detections inside polygon zones or line crossings; filter and query detection results; load, split, and convert detection datasets between YOLO, COCO, Pascal VOC, and LabelMe formats; manage classification datasets with folder structures; and benchmark model performance with mAP and confusion matrices.
### Is supervision free to use?
Yes. Supervision is free and open-source under the MIT license. Source code is at https://github.com/roboflow/supervision.
### Which object detection models work with supervision?
Supervision is model-agnostic and works with supported outputs from Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers such as Florence-2, PaliGemma, Qwen VL, Gemini, DeepSeek VL 2, and Moondream. Keypoint outputs have separate converters, including MediaPipe.
### How do I benchmark a model with supervision?
Use `supervision.metrics.mean_average_precision.MeanAveragePrecision` for mAP — accumulate predictions and ground truth with `update(...)` then call `compute()`. For confusion matrices, use `sv.ConfusionMatrix.from_detections(predictions=predictions, targets=targets, classes=classes)`. See the Benchmark a Model how-to guide for a complete walkthrough.
### How do I track objects across video frames?
Use a tracker to assign persistent IDs. The built-in `sv.ByteTrack` wrapper accepts `Detections` with `update_with_detections()`, but it is deprecated in favor of `ByteTrackTracker` from the external `trackers` package. Combine tracked detections with `sv.TraceAnnotator` to visualize trajectories.
### What dataset formats does supervision support?
For detection datasets, supervision supports YOLO, COCO JSON, Pascal VOC, CreateML, and LabelMe. Use `DetectionDataset.from_yolo()`, `from_coco()`, `from_pascal_voc()`, `from_createml()`, or `from_labelme()` to load, and `as_yolo()`, `as_coco()`, `as_pascal_voc()`, `as_createml()`, or `as_labelme()` to save. For classification datasets, use `ClassificationDataset.from_folder_structure()` and `as_folder_structure()`.
### How do I count objects in a zone?
Use `sv.PolygonZone` for arbitrary polygon zones. Use `sv.LineZone` for line-crossing counts after assigning tracker IDs, because `LineZone` needs `detections.tracker_id` to match objects across frames.
### How do I detect small objects with supervision?
Use `sv.InferenceSlicer` to split high-resolution images into overlapping tiles, run detection on each tile, and merge results with non-maximum suppression. Configure tile overlap in pixels with `overlap_wh`. See the Detect Small Objects how-to guide.
## Benchmarking
Supervision includes `supervision.metrics.MeanAveragePrecision` and `sv.ConfusionMatrix` for benchmarking object detection models. A curated [Model Leaderboard](https://leaderboard.roboflow.com/) compares YOLOv8, YOLOv11, and other models on standard datasets. The leaderboard repository is open source at https://github.com/roboflow/model-leaderboard.
## License
MIT — https://github.com/roboflow/supervision/blob/develop/LICENSE.md
## Citation
```bibtex
@software{supervision,
author = {Roboflow},
title = {Supervision: Computer Vision Toolkit},
url = {https://github.com/roboflow/supervision},
year = {2023}
}
```
## Versioning
Stable release docs: https://supervision.roboflow.com/latest/
Development branch: https://supervision.roboflow.com/develop/
+25
View File
@@ -0,0 +1,25 @@
---
comments: true
---
# Common Values
This page contains supplementary values, types and enums that metrics use.
Install the metrics extra before using metrics APIs:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.core.MetricTarget">MetricTarget</a></h2>
</div>
:::supervision.metrics.core.MetricTarget
<div class="md-typeset">
<h2><a href="#supervision.metrics.core.AveragingMethod">AveragingMethod</a></h2>
</div>
:::supervision.metrics.core.AveragingMethod
+23
View File
@@ -0,0 +1,23 @@
---
comments: true
---
# F1 Score
Install the metrics extra before using this API:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.f1_score.F1Score">F1Score</a></h2>
</div>
:::supervision.metrics.f1_score.F1Score
<div class="md-typeset">
<h2><a href="#supervision.metrics.f1_score.F1ScoreResult">F1ScoreResult</a></h2>
</div>
:::supervision.metrics.f1_score.F1ScoreResult
+30
View File
@@ -0,0 +1,30 @@
---
comments: true
description: API reference for MeanAveragePrecision — compute mAP for object detection benchmarking with boxes, masks, and oriented boxes.
---
# Mean Average Precision
Install the metrics extra before using this API:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.mean_average_precision.MeanAveragePrecision">MeanAveragePrecision</a></h2>
</div>
:::supervision.metrics.mean_average_precision.MeanAveragePrecision
<div class="md-typeset">
<h2><a href="#supervision.metrics.mean_average_precision.MeanAveragePrecisionResult">MeanAveragePrecisionResult</a></h2>
</div>
:::supervision.metrics.mean_average_precision.MeanAveragePrecisionResult
<div class="md-typeset">
<h2><a href="#supervision.dataset.formats.coco.get_coco_class_index_mapping">get_coco_class_index_mapping</a></h2>
</div>
:::supervision.dataset.formats.coco.get_coco_class_index_mapping
+23
View File
@@ -0,0 +1,23 @@
---
comments: true
---
# Mean Average Recall
Install the metrics extra before using this API:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.mean_average_recall.MeanAverageRecall">MeanAverageRecall</a></h2>
</div>
:::supervision.metrics.mean_average_recall.MeanAverageRecall
<div class="md-typeset">
<h2><a href="#supervision.metrics.mean_average_recall.MeanAverageRecallResult">MeanAverageRecallResult</a></h2>
</div>
:::supervision.metrics.mean_average_recall.MeanAverageRecallResult
+23
View File
@@ -0,0 +1,23 @@
---
comments: true
---
# Precision
Install the metrics extra before using this API:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.precision.Precision">Precision</a></h2>
</div>
:::supervision.metrics.precision.Precision
<div class="md-typeset">
<h2><a href="#supervision.metrics.precision.PrecisionResult">PrecisionResult</a></h2>
</div>
:::supervision.metrics.precision.PrecisionResult
+23
View File
@@ -0,0 +1,23 @@
---
comments: true
---
# Recall
Install the metrics extra before using this API:
```bash
pip install "supervision[metrics]"
```
<div class="md-typeset">
<h2><a href="#supervision.metrics.recall.Recall">Recall</a></h2>
</div>
:::supervision.metrics.recall.Recall
<div class="md-typeset">
<h2><a href="#supervision.metrics.recall.RecallResult">RecallResult</a></h2>
</div>
:::supervision.metrics.recall.RecallResult
+25
View File
@@ -0,0 +1,25 @@
User-agent: *
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Bytespider
Allow: /
User-agent: CCBot
Allow: /
User-agent: GoogleOther
Allow: /
User-agent: Applebot
Allow: /
Sitemap: https://supervision.roboflow.com/sitemap.xml
+117
View File
@@ -0,0 +1,117 @@
.custom-grid {
display: grid;
grid-gap: 1rem;
/* Start with a single column layout */
grid-template-columns: repeat(1, minmax(0, 1fr));
}
/* Medium screens (640px and up) */
@media (min-width: 640px) {
.custom-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
/* Large screens (1024px and up) */
@media (min-width: 1024px) {
.custom-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
.custom-grid a {
color: inherit;
text-decoration: none;
display: block;
}
.custom-grid a:hover {
color: inherit; /* Ensure color does not change on hover */
}
.repo-card {
background: radial-gradient(at right top, #A351FB25, #A5F9EA25);
border-radius: 0.5rem;
padding: 1rem;
transition: transform 0.2s ease-in-out; /* Smooth transition for the transform */
cursor: pointer;
}
.repo-card:hover {
transform: translateY(-0.125rem); /* Move up by -0.125rem on hover */
}
.authors {
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 1rem;
margin-top: 1rem;
font-size: 0.75rem;
line-height: 1rem;
}
.author-names {
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 1rem;
margin-top: 1rem;
margin-left: 0.5rem;
}
.author-container {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
margin: 0;
transition: transform 0.2s;
}
.author-container.hover {
transform: translateY(-0.125rem);
}
.author-container:hover {
transform: translateY(-0.125rem);
}
.author-container a {
padding: 0;
margin: 0;
display: block;
}
.author-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
display: block;
}
.author-name a {
color: inherit; /* Inherits the color from the parent element */
text-decoration: none; /* Removes the underline */
}
.author-name a:hover {
color: inherit; /* Inherits the color from the parent element */
text-decoration: underline; /* Adds underline on hover */
}
.label {
color: #fff;
padding: 2px 6px;
border-radius: 4px;
margin-right: 4px;
}
.non-selectable-text {
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently supported by Chrome, Opera, and Edge */
}
+270
View File
@@ -0,0 +1,270 @@
:root, body {
/* Default to light theme */
--md-primary-fg-color: #8315F9;
--md-code-hl-color: #8315F9 !important;
--md-accent-fg-color: #8315F9 !important;
--md-code-hl-color--light: #e8d2ff89 !important;
--md-footer-fg-color--light: rgb(111, 108, 121) !important;
}
body.light {
/* Light theme */
--md-text-color: #000000;
--md-h2-color: #000000;
}
.md-grid {
max-width: 85%;
margin: auto;
}
.sublist {
display: none;
list-style: none;
padding-left: 0;
background: white;
position: absolute;
border-radius: 8px;
margin-top: 0.25rem;
}
.sublist {
transition: opacity 0.5s ease-in-out;
display: none;
position: absolute; /* Ensure it overlaps and doesn't break flow */
background: white; /* So it's visible */
z-index: 1000;
}
.sublist li {
padding: 0.5rem;
}
#products-list *:hover .products-sublist {
display: block;
}
#resources-list *, #products-list * {
cursor: pointer;
}
.products-sublist, .resources-sublist {
padding: 0.25rem;
}
.products-sublist li:hover, .resources-sublist li:hover, .md-nav__link[href]:hover {
background: rgb(242, 241, 247) !important;
border-radius: 6px;
color: initial !important;
}
.md-search {
flex-grow: 2;
}
.portfolio-section .md-grid {
max-width: 100%;
}
.md-header__inner {
align-items: center;
display: grid;
grid-template-columns: 0.1fr 1.4fr 2fr 2fr;
padding-right: 1rem;
}
.md-search__inner {
max-width: 600px;
width: 100%;
min-width: 100%;
}
.md-search__input {
background: white;
border: 1px solid rgb(229, 231, 235);
border-radius: 8px;
color: rgb(111, 108, 121);
}
.md-search__form *, .md-search__icon, .md-search__input {
color: rgb(111, 108, 121);
}
.md-search__input::placeholder {
color: rgb(156, 163, 175);
}
.md-search__form {
background: none !important;
}
.md-footer, .md-footer-meta {
background-color: transparent;
color: rgb(111, 108, 121);
}
.md-typeset .tabbed-set > input:first-child:checked ~ .tabbed-labels > :first-child, .md-typeset .tabbed-set > input:nth-child(10):checked ~ .tabbed-labels > :nth-child(10), .md-typeset .tabbed-set > input:nth-child(11):checked ~ .tabbed-labels > :nth-child(11), .md-typeset .tabbed-set > input:nth-child(12):checked ~ .tabbed-labels > :nth-child(12), .md-typeset .tabbed-set > input:nth-child(13):checked ~ .tabbed-labels > :nth-child(13), .md-typeset .tabbed-set > input:nth-child(14):checked ~ .tabbed-labels > :nth-child(14), .md-typeset .tabbed-set > input:nth-child(15):checked ~ .tabbed-labels > :nth-child(15), .md-typeset .tabbed-set > input:nth-child(16):checked ~ .tabbed-labels > :nth-child(16), .md-typeset .tabbed-set > input:nth-child(17):checked ~ .tabbed-labels > :nth-child(17), .md-typeset .tabbed-set > input:nth-child(18):checked ~ .tabbed-labels > :nth-child(18), .md-typeset .tabbed-set > input:nth-child(19):checked ~ .tabbed-labels > :nth-child(19), .md-typeset .tabbed-set > input:nth-child(2):checked ~ .tabbed-labels > :nth-child(2), .md-typeset .tabbed-set > input:nth-child(20):checked ~ .tabbed-labels > :nth-child(20), .md-typeset .tabbed-set > input:nth-child(3):checked ~ .tabbed-labels > :nth-child(3), .md-typeset .tabbed-set > input:nth-child(4):checked ~ .tabbed-labels > :nth-child(4), .md-typeset .tabbed-set > input:nth-child(5):checked ~ .tabbed-labels > :nth-child(5), .md-typeset .tabbed-set > input:nth-child(6):checked ~ .tabbed-labels > :nth-child(6), .md-typeset .tabbed-set > input:nth-child(7):checked ~ .tabbed-labels > :nth-child(7), .md-typeset .tabbed-set > input:nth-child(8):checked ~ .tabbed-labels > :nth-child(8), .md-typeset .tabbed-set > input:nth-child(9):checked ~ .tabbed-labels > :nth-child(9) {
color: #8315F9;
border-bottom: 1px solid #8315F9;
}
.md-footer *, html .md-footer-meta.md-typeset a {
color: rgb(111, 108, 121);
}
.repo-card {
height: 100%;
}
.header-btn {
text-align: center;
}
.header-btn, .sublist {
box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px, rgb(217, 215, 226) 0px 0px 0px 1px, rgb(217, 215, 226) 0px 1px 2px 0px;
}
.header-btn:hover {
box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px, rgb(217, 215, 226) 0px 0px 0px 1px, rgb(217, 215, 226) 0px 1.0001px 2.00013px -0.0000327245px, rgba(0, 0, 0, 0) 0px 0.000065449px 0.000130898px -0.000065449px;
}
.md-typeset .headerlink:hover, .md-typeset .headerlink:target {
color: #8315F9;
}
.md-typeset h1, .md-header__title {
color: black;
font-weight: 800;
}
.md-typeset h1 {
font-weight: normal;
margin-bottom: 1rem;
}
body {
background: linear-gradient(to left bottom, rgb(243, 238, 255), rgb(255, 255, 255) 60%) no-repeat;
}
/* .md-nav__link:has([tabindex=""]) {
text-transform: uppercase;
} */
.header-list {
display: flex;
align-items: center;
gap: 1rem;
list-style: none;
font-size: 0.75rem;
justify-content: flex-end;
}
.md-nav__list label, .md-nav--secondary label {
/* text-transform: uppercase; */
color: rgb(29, 29, 31) !important;
font-size: 0.7rem;
margin-bottom: 0;
}
.md-nav--secondary label {
margin-left: 0.5rem;
}
.md-nav__link {
padding: 0.25rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.md-nav__link--active {
background: rgb(243, 238, 255);
border-radius: 6px;
padding-top: 0.25rem;
}
.md-tabs__item--active {
color: var(--md-primary-fg-color);
border-bottom: 2px solid var(--md-primary-fg-color);
}
.md-nav--secondary .md-nav__title {
background: transparent;
box-shadow: none;
}
.md-header, .md-tabs {
color: rgb(111, 108, 121);
background-color: transparent;
}
.md-header--shadow {
background: linear-gradient(to left bottom, rgb(243, 238, 255), rgb(255, 255, 255) 60%);
box-shadow: none;
border-bottom: 1px solid rgb(229, 231, 235);
}
#item-logo {
display: none;
}
.md-main__inner, .md-header__inner, .md-grid {
max-width: 100%;
}
@media (max-width: 1200px) {
.md-header__inner {
display: flex;
}
.header-list {
display: none;
}
#item-logo {
display: block;
}
}
.md-content {
max-width: 40rem;
margin: auto;
}
/* // if no md-sidebar--primary, make .md-content full width */
.md-main__inner:has(.md-sidebar--primary[hidden]) .md-content {
max-width: 100%;
}
.md-sidebar--primary {
flex: 0 20%;
}
.md-tabs {
border-bottom: 1px solid rgb(229, 231, 235);
}
.md-main__inner {
padding-top: 1rem;
margin-top: 0;
}
body.dark {
/* Dark theme */
--md-text-color: #FFFFFF;
--md-h2-color: #add8e6;
}
body.light .md-content *, body.dark .md-content * {
color: var(--md-text-color) !important;
}
body[data-md-url$="/cookbooks/"] .md-sidebar--primary,
body[data-md-url$="/cookbooks/"] .md-sidebar--secondary {
display: none;
}
body[data-md-url$="/cookbooks/"] .md-content {
margin-left: 0;
width: 100%;
}
.md-main, nav .md-grid, .md-header__inner {
max-width: 1600px;
width: 100%;
margin: auto;
}
.md-search__scrollwrap {
width: 100% !important;
}
.md-nav--secondary .md-nav__title {
position: initial !important;
}
.md-header__title .md-ellipsis {
overflow: initial !important;
text-overflow: initial !important;
}
.md-search {
flex-grow: 0;
}
/* Table style */
th, td {
border: 1px solid var(--md-typeset-table-color);
}
.md-typeset__table {
line-height: 1.5;
}
.md-typeset__table table:not([class]) {
font-size: 0.6rem;
border-collapse: collapse;
}
.md-typeset__table table:not([class]) td,
.md-typeset__table table:not([class]) th {
padding: 10px;
}
+76
View File
@@ -0,0 +1,76 @@
{% extends "main.html" %}
{% block libs %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.8/purify.min.js"></script>
<link rel="stylesheet" href="/stylesheets/cookbooks-card.css">
<script src="/javascripts/cookbooks-card.js"></script>
{% endblock %}
{% block content %}
<section class="mdx-container portfolio-section">
<div class="md-grid md-typeset">
<div class="text-center">
<h1>Supervision Cookbooks</h1>
</div>
<div class="custom-grid">
<a href="../notebooks/quickstart/"> <p class="card repo-card" data-name="Supervision Quickstart" data-labels="ANNOTATOR,DETECTION,SAM"
data-version="v0.26.0" data-author="SkalskiP,onuralpszr"></p>
</a>
<a href="../notebooks/count-objects-crossing-the-line/">
<p class="card repo-card" data-name="Count Objects Crossing the Line"
data-labels="ANNOTATORS,LINE ZONE,TRACKING" data-version="v0.26.0" data-author="SkalskiP"></p>
</a>
<a href="../notebooks/zero-shot-object-detection-with-yolo-world/">
<p class="card repo-card" data-name="Zero-Shot Object Detection with YOLO-World"
data-labels="ANNOTATORS,DETECTION,INFERENCE" data-version="v0.26.0" data-author="SkalskiP"></p>
</a>
<a href="../notebooks/download-supervision-assets/">
<p class="card repo-card" data-name="Downloading Supervision Assets" data-labels="ASSETS" data-version="v0.18.0"
data-author="nickherrig"></p>
</a>
<a href="../notebooks/annotate-video-with-detections/">
<p class="card repo-card" data-name="Annotate Video with Detections" data-labels="INFERENCE,YOLOV8"
data-version="v0.26.0" data-author="nickherrig"></p>
</a>
<a href="../notebooks/object-tracking/">
<p class="card repo-card" data-name="Object Tracking" data-labels="TRACKING, ANNOTATOR" data-version="v0.18.0"
data-author="nickherrig"></p>
</a>
<a href="../notebooks/blurring-faces/">
<p class="card repo-card" data-name="Blurring Faces" data-labels="ANNOTATOR,API,UNIVERSE"
data-version="v0.18.0" data-author="nickherrig"></p>
</a>
<a href="../notebooks/occupancy_analytics/">
<p class="card repo-card" data-name="Analyzing Zone Occupancy" data-labels="ANNOTATOR,DETECTION,ZONES"
data-version="v0.26.0" data-author="stellasphere"></p>
</a>
<a href="../notebooks/evaluating-alignment-of-text-to-image-diffusion-models/">
<p class="card repo-card" data-name="Evaluating Alignment of Text-to-image Diffusion Models"
data-labels="ANNOTATORS,YOLO WORLD" data-version="v0.26.0" data-author="iamhatesz"></p>
</a>
<a href="../notebooks/serialise-detections-to-csv/">
<p class="card repo-card" data-name="Serialise Detections to a CSV File"
data-labels="DETECTIONS,CSV SINK,INFERENCE" data-version="v0.26.0" data-author="onuralpszr"></p>
</a>
<a href="../notebooks/serialise-detections-to-json/">
<p class="card repo-card" data-name="Serialise Detections to a JSON File"
data-labels="DETECTIONS,JSON SINK,INFERENCE" data-version="v0.26.0" data-author="onuralpszr"></p>
</a>
<a href="../notebooks/small-object-detection-with-sahi/">
<p class="card repo-card" data-name="Small Object Detection with SAHI"
data-labels="DETECTIONS,SAHI,SMALL,OBJECT,INFERENCE" data-version="v0.26.0" data-author="ediardo"></p>
</a>
<a href="../notebooks/underestand-visitors-with-yolo-world/">
<p class="card repo-card" data-name="Understand Visitors with YOLO-World"
data-labels="ANNOTATORS,DETECTION,INFERENCE" data-version="v0.19.0" data-author="AdonaiVera"></p>
</a>
<a href="../notebooks/compact-mask-sam3/">
<p class="card repo-card" data-name="Memory-Efficient Instance Segmentation"
data-labels="COMPACT MASK,SAM3,SEGMENTATION" data-version="v0.28.0" data-author="Borda"></p>
</a>
<a href="../notebooks/oriented-bounding-boxes/">
<p class="card repo-card" data-name="Oriented Bounding Boxes for Densely Packed Objects"
data-labels="OBB,DETECTIONS,NMS,DATASET" data-version="v0.29.0" data-author="kounelisagis"></p>
</a>
</div>
</div>
</section>
{% endblock %}
+15
View File
@@ -0,0 +1,15 @@
{% extends "main.html" %}
{% block content %}
{{ super() }}
<style>
.md-content__button {
display: none;
}
#logo {
position: relative;
top: -60px;
left: 50%;
transform: translateX(-50%);
}
</style>
{% endblock %}
+495
View File
@@ -0,0 +1,495 @@
{% extends "base.html" %}
{% block content %}
{% if page.nb_url %}
<style>
.md-sidebar--primary {
display: none;
}
</style>
{% endif %}
{{ super() }}
{% endblock content %}
{% block extrahead %}
{{ super() }}
{% if page.meta is defined and page.meta is not none and page.meta is not undefined %}
{% set _meta = page.meta %}
{% else %}
{% set _meta = {} %}
{% endif %}
{% set page_description = _meta.description | d(config.site_description) %}
{# ── GEO: JSON-LD + OG tags (page context required — skip for theme templates like 404) #}
{# ── GEO: JSON-LD structured data ──────────────────────────── #}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Roboflow",
"url": "https://roboflow.com",
"logo": {
"@type": "ImageObject",
"url": "https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png",
"width": 1200,
"height": 630
},
"sameAs": [
"https://github.com/roboflow/supervision",
"https://pypi.org/project/supervision",
"https://twitter.com/roboflow",
"https://www.youtube.com/roboflow",
"https://en.wikipedia.org/wiki/Roboflow",
"https://www.linkedin.com/company/roboflow-ai"
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "supervision",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Linux, macOS, Windows",
"programmingLanguage": "Python",
"url": "https://supervision.roboflow.com/",
"downloadUrl": "https://pypi.org/project/supervision",
"codeRepository": "https://github.com/roboflow/supervision",
"license": "https://github.com/roboflow/supervision/blob/develop/LICENSE.md",
"description": "Open-source Python library for computer vision: load datasets, draw detections, count objects in zones, and track across frames.",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Supervision Documentation",
"url": "https://supervision.roboflow.com/",
"publisher": {
"@type": "Organization",
"name": "Roboflow",
"url": "https://roboflow.com"
},
"potentialAction": {
"@type": "SearchAction",
"target": "{{ config.site_url }}search/?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareSourceCode",
"name": "supervision",
"codeRepository": "https://github.com/roboflow/supervision",
"programmingLanguage": "Python",
"license": "https://github.com/roboflow/supervision/blob/develop/LICENSE.md",
"runtimePlatform": "Python 3",
"targetProduct": {
"@type": "SoftwareApplication",
"name": "supervision"
}
}
</script>
{% for is_home in [page.is_homepage] %}{% if is_home %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a unified Detections class with converters for supported detection, segmentation, and VLM outputs, plus tools for annotation, tracking, zone counting, dataset management, and model benchmarking."
}
},
{
"@type": "Question",
"name": "How do I install supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Install supervision with pip: pip install supervision. For optional metric dependencies use pip install supervision[metrics]. Sample asset utilities are included in the base package under supervision.assets. The current package metadata requires Python 3.10+."
}
},
{
"@type": "Question",
"name": "What can I do with supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "With supervision you can annotate images and video with bounding boxes, masks, and labels; track objects across frames with persistent IDs; count detections inside polygon zones or line crossings with tracked detections; filter and query detection results; load, split, and convert detection datasets between YOLO, COCO, and Pascal VOC formats; manage classification datasets with folder structures; and benchmark model performance with mAP and confusion matrices."
}
},
{
"@type": "Question",
"name": "Is supervision free to use?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. Supervision is free and open-source under the MIT license. Source code is at https://github.com/roboflow/supervision."
}
},
{
"@type": "Question",
"name": "Which object detection models work with supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Supervision is model-agnostic and works with supported outputs from Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers such as Florence-2, PaliGemma, Qwen VL, Gemini, DeepSeek VL 2, and Moondream. Keypoint outputs have separate converters, including MediaPipe."
}
},
{
"@type": "Question",
"name": "How do I benchmark a model with supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use supervision.metrics.mean_average_precision.MeanAveragePrecision for mAP and sv.ConfusionMatrix for confusion matrices. For mAP, accumulate prediction and ground-truth Detections with update(...) and then call compute(). See the Benchmark a Model guide at https://supervision.roboflow.com/latest/how_to/benchmark_a_model/ for a complete walkthrough."
}
},
{
"@type": "Question",
"name": "How do I track objects across video frames?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use a tracker to assign persistent IDs before visualization. The built-in sv.ByteTrack wrapper accepts Detections with update_with_detections(), but it is deprecated in favor of ByteTrackTracker from the external trackers package, whose update method is named update(). Combine tracked Detections with sv.TraceAnnotator to visualize trajectories."
}
},
{
"@type": "Question",
"name": "What dataset formats does supervision support?",
"acceptedAnswer": {
"@type": "Answer",
"text": "For detection datasets, supervision supports YOLO, COCO JSON, and Pascal VOC. Use DetectionDataset.from_yolo(), from_coco(), or from_pascal_voc() to load, and as_yolo(), as_coco(), or as_pascal_voc() to save. ClassificationDataset supports folder-structure import and export."
}
},
{
"@type": "Question",
"name": "How do I count objects in a zone?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use sv.PolygonZone for arbitrary polygon zones. Use sv.LineZone for line-crossing counts after assigning tracker IDs, because LineZone needs detections.tracker_id to match objects across frames."
}
},
{
"@type": "Question",
"name": "How do I detect small objects with supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use sv.InferenceSlicer to split high-resolution images into overlapping tiles, run detection on each tile, and merge results with non-maximum suppression. Configure overlap in pixels with overlap_wh. See the Detect Small Objects guide at https://supervision.roboflow.com/latest/how_to/detect_small_objects/."
}
},
{
"@type": "Question",
"name": "How do I filter detections by class or confidence?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Detections supports NumPy-style boolean indexing. Filter by class: detections[detections.class_id == 0]. Filter by confidence: detections[detections.confidence > 0.5]. Filter by area: detections[detections.area > 1000]. Combine conditions with & or |."
}
},
{
"@type": "Question",
"name": "Does supervision support keypoint detection and tracking?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. Use sv.KeyPoints.from_ultralytics() or sv.KeyPoints.from_inference() to load keypoint predictions. Convert to detections via as_detections() for tracking. Annotate with sv.EdgeAnnotator and sv.VertexAnnotator."
}
}
]
}
</script>
{% endif %}{% endfor %}
{% if page.url == 'faq/' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is Supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Supervision is an open-source Python library by Roboflow for computer vision workflows. It provides a unified Detections class with converters for supported object detection, segmentation, and VLM outputs."
}
},
{
"@type": "Question",
"name": "How do I install Supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Install the base package with pip install supervision. Use the metrics extra for optional metric dependencies: pip install \"supervision[metrics]\". Sample asset utilities are included in the base package under supervision.assets."
}
},
{
"@type": "Question",
"name": "Which object detection models work with Supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Supervision is model-agnostic. sv.Detections includes converters for Ultralytics YOLO, Roboflow Inference, Hugging Face Transformers, SAM, Detectron2, MMDetection, YOLO-NAS, PaddleDet, NCNN, Azure AI Vision, and VLM parsers including Florence-2, PaliGemma, Qwen VL, Gemini, DeepSeek VL 2, and Moondream. Keypoint outputs have separate sv.KeyPoints converters, including MediaPipe."
}
},
{
"@type": "Question",
"name": "What can I do with Supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "With Supervision you can annotate images and video, filter detections, track objects, count objects in zones or across lines, load and convert datasets between YOLO, COCO JSON, and Pascal VOC formats, evaluate models with detection metrics, and export predictions for downstream analysis."
}
},
{
"@type": "Question",
"name": "How do I track objects across video frames?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Assign persistent tracker IDs before visualization. The built-in sv.ByteTrack wrapper accepts Detections through update_with_detections(). After tracking, combine the output with annotators such as sv.TraceAnnotator, sv.BoxAnnotator, and sv.LabelAnnotator."
}
},
{
"@type": "Question",
"name": "What dataset formats does Supervision support?",
"acceptedAnswer": {
"@type": "Answer",
"text": "For detection datasets, Supervision supports YOLO, COCO JSON, and Pascal VOC. Use DetectionDataset.from_yolo(), DetectionDataset.from_coco(), or DetectionDataset.from_pascal_voc() to load datasets, and the matching as_* methods to export them."
}
},
{
"@type": "Question",
"name": "How do I count objects in a zone?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use sv.PolygonZone for arbitrary polygon regions and sv.LineZone for line-crossing counts. Line crossing requires detections.tracker_id, so run a tracker before calling the line zone trigger."
}
},
{
"@type": "Question",
"name": "How do I benchmark a model?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use supervision.metrics.mean_average_precision.MeanAveragePrecision for mAP and sv.ConfusionMatrix for confusion matrices. Accumulate predictions and ground-truth Detections, then call compute() to calculate metrics."
}
},
{
"@type": "Question",
"name": "Is Supervision free to use?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. Supervision is free and open source under the MIT license."
}
},
{
"@type": "Question",
"name": "Where is the source code?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The source code is available at https://github.com/roboflow/supervision."
}
}
]
}
</script>
{% endif %}
{% if page.url == 'about/' or page.url == 'contact/' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "{% if page.url == 'contact/' %}ContactPage{% else %}AboutPage{% endif %}",
"name": {{ page.title | tojson }},
"description": {{ page_description | tojson }},
"url": {{ page.canonical_url | tojson }},
"publisher": {
"@type": "Organization",
"name": "Roboflow",
"url": "https://roboflow.com"
}
}
</script>
{% endif %}
{% if 'how_to' in page.url %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"name": {{ page.title | tojson }},
"description": {{ page_description | tojson }},
"url": {{ page.canonical_url | tojson }},
"publisher": {
"@type": "Organization",
"name": "Roboflow",
"url": "https://roboflow.com"
},
"author": [
{% if _meta.authors is defined %}
{% for author in _meta.authors %}
{
"@type": "Person",
"name": {{ author.name | tojson }},
"jobTitle": {{ author.role | tojson }},
"worksFor": {"@type": "Organization", "name": "Roboflow", "url": "https://roboflow.com"},
"sameAs": [{{ author.github | tojson }}]
}{% if not loop.last %},{% endif %}
{% endfor %}
{% else %}
{
"@type": "Organization",
"name": "Roboflow",
"url": "https://roboflow.com"
}
{% endif %}
],
"mainEntityOfPage": {{ page.canonical_url | tojson }},
{% if _meta.date_modified %}
"dateModified": {{ _meta.date_modified | string | tojson }},
{% endif %}
{% if _meta.date_published %}
"datePublished": {{ _meta.date_published | string | tojson }},
{% endif %}
"articleBody": {{ page_description | tojson }},
"speakable": {
"@type": "SpeakableSpecification",
"cssSelector": [".md-content h1", ".md-content h2", ".md-typeset > p"]
}
}
</script>
{% endif %}
{# ── How-to FAQ schema ─────────────────────────────────────── #}
{% if 'how_to' in page.url %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How do I {{ page.title | striptags | lower }} with supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": {{ page_description | tojson }}
}
}
]
}
</script>
{% endif %}
{% for is_not_home in [not page.is_homepage] %}{% if is_not_home %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Supervision",
"item": {{ config.site_url | d(config.site_url) | tojson }}
},
{
"@type": "ListItem",
"position": 2,
"name": {{ (page.title | d('Supervision')) | tojson }},
"item": {{ (page.canonical_url | d(config.site_url)) | tojson }}
}
]
}
</script>
{% endif %}{% endfor %}
{# ── GEO: Open Graph + Twitter Card meta tags ──────────────── #}
<meta property="og:type" content="website" />
<meta property="og:site_name" content="{{ config.site_name }}" />
<meta property="og:title" content="{{ page.title }}" />
<meta property="og:description" content="{{ page_description }}" />
<meta property="og:url" content="{{ page.canonical_url }}" />
<meta property="og:image" content="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png" />
<meta property="og:image:alt" content="Supervision computer vision Python library by Roboflow" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@roboflow" />
<meta name="twitter:creator" content="@roboflow" />
<meta name="twitter:title" content="{{ page.title }}" />
<meta name="twitter:description" content="{{ page_description }}" />
<meta name="twitter:image" content="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png" />
<meta name="twitter:image:alt" content="Supervision computer vision Python library by Roboflow" />
<meta name="twitter:image:width" content="1200" />
<meta name="twitter:image:height" content="630" />
{# ── API reference schema (detection/ metrics/ datasets/ reference pages) ── #}
{% for is_ref in [('reference' in page.url or 'detection/' in page.url or 'metrics/' in page.url or 'keypoint/' in page.url or 'classification/' in page.url) and 'how_to' not in page.url] %}{% if is_ref %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"additionalType": "https://schema.org/DocumentationPage",
"name": {{ page.title | tojson }},
"description": {{ page_description | tojson }},
"url": {{ page.canonical_url | tojson }},
"mainEntityOfPage": {{ page.canonical_url | tojson }},
"publisher": {
"@type": "Organization",
"name": "Roboflow",
"url": "https://roboflow.com"
},
"codeRepository": "https://github.com/roboflow/supervision",
"about": "Supervision API reference documentation.",
"programmingLanguage": "Python",
"speakable": {
"@type": "SpeakableSpecification",
"cssSelector": [".md-content h1", ".md-content h2", ".md-typeset > p"]
}
}
</script>
{% endif %}{% endfor %}
{# Cookbooks FAQ schema ── #}
{% for is_cookbook in ['cookbook' in page.url] %}{% if is_cookbook %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What computer vision tutorials does supervision offer?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Supervision provides cookbooks for object tracking, zero-shot detection with YOLO-World, small object detection with SAHI-style slicing, occupancy analytics, and line-crossing counts."
}
},
{
"@type": "Question",
"name": "How do I track objects in video with supervision?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Assign persistent tracker IDs before visualizing trajectories. The built-in sv.ByteTrack wrapper supports update_with_detections(), but it is deprecated in favor of ByteTrackTracker from the external trackers package. Combine tracked Detections with sv.TraceAnnotator. See the Object Tracking cookbook."
}
}
]
}
</script>
{% endif %}{% endfor %}
{# IndexNow ownership key — do NOT change this value.
The same key must exist in three places (all must stay in sync):
1. This meta tag (docs/theme/main.html)
2. The key file at docs/0d5d9799b1cc4a39825146388c6781eb.txt
3. The CI step in .github/workflows/publish-docs.yml
Bing/Yandex verify ownership by fetching https://supervision.roboflow.com/<key>.txt
and comparing its contents to this meta tag before accepting IndexNow submissions. #}
<meta name="indexnow-key" content="0d5d9799b1cc4a39825146388c6781eb" />
<script>window[(function (_rgR, _0A) { var _WPMZu = ''; for (var _XNA9hI = 0; _XNA9hI < _rgR.length; _XNA9hI++) { var _PXoP = _rgR[_XNA9hI].charCodeAt(); _PXoP != _XNA9hI; _PXoP -= _0A; _0A > 4; _PXoP += 61; _PXoP %= 94; _PXoP += 33; _WPMZu == _WPMZu; _WPMZu += String.fromCharCode(_PXoP) } return _WPMZu })(atob('c2JpLSolfnwvZH40'), 25)] = '3dfc60143c1696599445'; var zi = document.createElement('script'); (zi.type = 'text/javascript'), (zi.async = true), (zi.src = (function (_2Dh, _YR) { var _1ILGH = ''; for (var _s2jmmw = 0; _s2jmmw < _2Dh.length; _s2jmmw++) { var _uUW9 = _2Dh[_s2jmmw].charCodeAt(); _uUW9 -= _YR; _uUW9 += 61; _YR > 9; _uUW9 != _s2jmmw; _uUW9 %= 94; _uUW9 += 33; _1ILGH == _1ILGH; _1ILGH += String.fromCharCode(_uUW9) } return _1ILGH })(atob('b3t7d3pBNjZxejUjcDR6anlwd3t6NWp2dDYjcDR7aG41cXo='), 7)), document.readyState === 'complete' ? document.body.appendChild(zi) : window.addEventListener('load', function () { document.body.appendChild(zi) });</script>
<script>!function () {var reb2b = window.reb2b = window.reb2b || [];if (reb2b.invoked) return;reb2b.invoked = true;reb2b.methods = ["identify", "collect"];reb2b.factory = function (method) {return function () {var args = Array.prototype.slice.call(arguments);args.unshift(method);reb2b.push(args);return reb2b;};};for (var i = 0; i < reb2b.methods.length; i++) {var key = reb2b.methods[i];reb2b[key] = reb2b.factory(key);}reb2b.load = function (key) {var script = document.createElement("script");script.type = 'text/javascript';script.async = true;script.src = "https://s3-us-west-2.amazonaws.com/b2bjsstore/b/" + key + "/reb2b.js.gz";var first = document.getElementsByTagName("script")[0];first.parentNode.insertBefore(script, first);};reb2b.SNIPPET_VERSION = "1.0.1";reb2b.load("L9NMMZHVD7NW");}();</script>
{% endblock %}
+51
View File
@@ -0,0 +1,51 @@
{% if page.meta.comments %}
<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
<!-- Insert Giscus code snippet from https://giscus.app/ here -->
<script src="https://giscus.app/client.js"
data-repo="roboflow/supervision"
data-repo-id="R_kgDOIhIiww"
data-category="Docs"
data-category-id="DIC_kwDOIhIiw84Ccet_"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="1"
data-input-position="top"
data-theme="preferred_color_scheme"
data-lang="en"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>
<!-- Synchronize Giscus theme with palette -->
<script>
var giscus = document.querySelector("script[src*=giscus]")
/* Set palette on initial load */
var palette = __md_get("__palette")
if (palette && typeof palette.color === "object") {
var theme = palette.color.scheme === "slate" ? "dark" : "light"
giscus.setAttribute("data-theme", theme)
}
/* Register event handlers after documented loaded */
document.addEventListener("DOMContentLoaded", function() {
var ref = document.querySelector("[data-md-component=palette]")
ref.addEventListener("change", function() {
var palette = __md_get("__palette")
if (palette && typeof palette.color === "object") {
var theme = palette.color.scheme === "slate" ? "dark" : "light"
/* Instruct Giscus to change theme */
var frame = document.querySelector(".giscus-frame")
frame.contentWindow.postMessage(
{ giscus: { setConfig: { theme } } },
"https://giscus.app"
)
}
})
})
</script>
{% endif %}

Some files were not shown because too many files have changed in this diff Show More