Merge branch 'develop' into add_nmm_to_detections to resolve conflicts

This commit is contained in:
mario-dg committed 2024-04-09 18:50:55 +02:00
commit 5f0dcc2cb2
192 files changed
+24333 -4793

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
version: 2
updates:
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
commit-message:
prefix: ⬆️
# Python
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
commit-message:
prefix: ⬆️
+33
View File
@@ -0,0 +1,33 @@
name: Clear cache
on:
schedule:
- cron: '0 0 1 * *'
workflow_dispatch:
permissions:
actions: write
jobs:
clear-cache:
runs-on: ubuntu-latest
steps:
- name: Clear cache
uses: actions/github-script@v7
with:
script: |
console.log("About to clear")
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
console.log(cache)
github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
}
console.log("Clear completed")
+43 -9
View File
@@ -1,19 +1,53 @@
name: Docs WorkFlow
name: Docs WorkFlow - Develop Tag 📚
on:
push:
branches:
- master
- main
- develop
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref}}
cancel-in-progress: true
permissions:
contents: write
pages: write
pull-requests: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: 🔄 Checkout code
uses: actions/checkout@v4
with:
python-version: 3.x
- run: pip install mkdocs-material
- run: pip install "mkdocstrings[python]"
- run: mkdocs gh-deploy --force
fetch-depth: 0
- name: 🐍 Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: 📦 Install mkdocs-material
run: pip install "mkdocs-material"
- name: 📦 Install mkdocstrings[python]
run: pip install "mkdocstrings[python]"
- name: 📦 Install mkdocs-material[imaging]
run: pip install "mkdocs-material[imaging]"
- name: 📦 Install mike
run: pip install "mike"
- name: 📦 Install mkdocs-git-revision-date-localized-plugin
run: pip install "mkdocs-git-revision-date-localized-plugin"
- name: 📦 Install JupyterLab
run: pip install jupyterlab
- name: 📦 Install mkdocs-jupyter
run: pip install mkdocs-jupyter
- name: 📦 Install mkdocs-git-committers-plugin-2
run: pip install mkdocs-git-committers-plugin-2
- name: ⚙️ Configure git for github-actions
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: 🚀 Deploy MkDoc-Material with mike
run: |
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} mike deploy --push develop
+10 -8
View File
@@ -6,22 +6,24 @@ on:
- '[0-9]+.[0-9]+[0-9]+.[0-9]+b[0-9]'
- '[0-9]+.[0-9]+[0-9]+.[0-9]+rc[0-9]'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build-n-publish:
name: Build and publish to PyPI
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10"]
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: 🐍 Set up Python 3.8 environment for build
uses: actions/setup-python@v4
- name: 🛎️ Checkout
uses: actions/checkout@v4
with:
python-version: "3.8"
ref: ${{ github.head_ref }}
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: 🏗️ Build source and wheel distributions
run: |
+3 -6
View File
@@ -3,10 +3,7 @@ on:
push:
tags:
- '[0-9]+.[0-9]+[0-9]+.[0-9]'
- '[0-9]+.[0-9]+[0-9]+.[0-9]'
- '[0-9]+.[0-9]+[0-9]+.[0-9]'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
@@ -14,14 +11,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8]
python-version: ["3.10"]
steps:
- name: 🛎️ Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
+34
View File
@@ -0,0 +1,34 @@
name: 🧪 Docs Test WorkFlow 📚
on:
pull_request:
branches: [main, develop]
jobs:
docs-build-test:
runs-on: ubuntu-latest
steps:
- name: 🔄 Checkout code
uses: actions/checkout@v4
- name: 🐍 Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: 📦 Install mkdocs-material
run: pip install "mkdocs-material[all]"
- name: 📦 Install mkdocstrings[python]
run: pip install "mkdocstrings[python]"
- name: 📦 Install mkdocs-material[imaging]
run: pip install "mkdocs-material[imaging]"
- name: 📦 Install mike
run: pip install "mike"
- name: 📦 Install mkdocs-git-revision-date-localized-plugin
run: pip install "mkdocs-git-revision-date-localized-plugin"
- name: 📦 Install JupyterLab
run: pip install jupyterlab
- name: 📦 Install mkdocs-jupyter
run: pip install mkdocs-jupyter
- name: 📦 Install mkdocs-git-committers-plugin-2
run: pip install mkdocs-git-committers-plugin-2
- name: 🧪 Test documentation build
run: mkdocs build --verbose
+58
View File
@@ -0,0 +1,58 @@
name: Python 3.8 - Min Dep Test WorkFlow
on:
pull_request:
branches: [main, develop]
jobs:
build-min-dep-test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8"]
steps:
- name: 🛎️ Checkout
uses: actions/checkout@v4
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
# id based on python version
id: python-setup
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: 📦 Install dependencies
run: |
python -m pip install --upgrade pip
pip install \
attrs==23.1.0 \
certifi==2023.7.22 \
charset-normalizer==2.0.12 \
cycler==0.12.1 \
exceptiongroup==1.1.3 \
fonttools==4.43.1 \
idna==3.4 \
iniconfig==2.0.0 \
kiwisolver==1.4.5 \
matplotlib==3.5.0 \
numpy==1.21.2 \
opencv-python==4.5.5.64 \
Pillow==10.1.0 \
packaging==23.2 \
pluggy==1.3.0 \
pyparsing==3.1.1 \
pytest==7.2.0 \
python-dateutil==2.8.2 \
PyYAML==5.3 \
requests==2.26.0 \
scipy==1.10.0 \
setuptools-scm==8.0.4 \
six==1.16.0 \
tomli==2.0.1 \
tqdm==4.62.3 \
typing_extensions==4.8.0 \
urllib3==1.26.18 \
defusedxml==0.7.1
- name: 🧪 Test
run: "python -m pytest ./test"
+9 -6
View File
@@ -5,22 +5,25 @@ on:
branches: [main, develop]
jobs:
build:
build-dev-test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10","3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- name: 🛎️ Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: 🦾 Install dependencies
check-latest: true
- name: 📦 Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .
pip install .
pip install pytest
- name: 🧪 Test
run: "python -m pytest ./test"
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
name: 👋 Welcome
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1.1.1
- uses: actions/first-interaction@v1.3.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: "Hello there, thank you for opening an Issue ! 🙏🏻 The team was notified and they will get back to you asap."
+20 -2
View File
@@ -133,5 +133,23 @@ dmypy.json
# Pyre type checker
.pyre/
# Notebooks
notebooks/
# 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-*
+8 -31
View File
@@ -7,18 +7,17 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: test/.*\.py
- id: check-yaml
- id: check-docstring-first
exclude: mkdocs.yml
- id: check-executables-have-shebangs
- id: check-toml
- id: check-case-conflict
- id: check-added-large-files
args: ['--maxkb=2048']
exclude: ^logo/
- id: detect-private-key
- id: forbid-new-submodules
- id: pretty-format-json
@@ -27,50 +26,28 @@ repos:
- id: end-of-file-fixer
- id: mixed-line-ending
# - repo: https://github.com/asottile/pyupgrade
# rev: v3.9.0
# hooks:
# - id: pyupgrade
# name: Upgrade code
# args: [--py38-plus]
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
name: Flake8 Checks
entry: flake8
additional_dependencies: [Flake8-pyproject]
- repo: https://github.com/PyCQA/bandit
rev: '1.7.5'
rev: '1.7.8'
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
additional_dependencies: ["bandit[toml]"]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
name: isort (python)
- id: isort
name: isort (cython)
types: [cython]
- id: isort
name: isort (pyi)
types: [pyi]
- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
rev: v0.3.5
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
types_or: [ python, pyi, jupyter ]
+1 -1
View File
@@ -15,7 +15,7 @@ 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 calcuation.
filtering to confusion matrix calculation.
keywords:
- computer vision
- image processing
+16 -3
View File
@@ -52,7 +52,7 @@ git push -u origin main
### Pre-commit tool
This project utilizes 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.
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.
@@ -76,7 +76,6 @@ All new functions and classes in `supervision` should include docstrings. This i
So far, **there is no type checking with mypy**. See [issue](https://github.com/roboflow-ai/template-python/issues/4).
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)
@@ -109,10 +108,24 @@ PRs must pass all tests and linting requirements before they can be merged.
The `supervision` documentation is stored in a folder called `docs`. The project documentation is built using `mkdocs`.
To run the documentation, install the project requirements with `poetry install dev`. Then, run `mkdocs serve` to start the documentation server.
To run the documentation, install the project requirements with `poetry install --with dev`. Then, run `mkdocs serve` to start the documentation server.
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/nodebooks`](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.
- Freeze the version of `supervision` you are using.
- 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
[`pytests`](https://docs.pytest.org/en/7.1.x/) is used to run our tests.
+151 -213
View File
@@ -1,6 +1,6 @@
<div align="center">
<p>
<a align="center" href="" target="_blank">
<a align="center" href="" target="https://supervision.roboflow.com">
<img
width="100%"
src="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png?updatedAt=1678995927529"
@@ -10,289 +10,226 @@
<br>
[notebooks](https://github.com/roboflow/notebooks) | [inference](https://github.com/roboflow/inference) | [autodistill](https://github.com/autodistill/autodistill) | [collect](https://github.com/roboflow/roboflow-collect)
[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)](https://github.com/roboflow/supervision/blob/main/LICENSE.md)
[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)
[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/main/demo.ipynb)
[![Discord](https://img.shields.io/discord/1159501506232451173)](https://discord.gg/GbfgXGJ8Bk)
[![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)](https://github.com/roboflow/supervision/blob/main/LICENSE.md)
[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/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)](https://discord.gg/GbfgXGJ8Bk)
[![built-with-material-for-mkdocs](https://img.shields.io/badge/Material_for_MkDocs-526CFE?logo=MaterialForMkDocs&logoColor=white)](https://squidfunk.github.io/mkdocs-material/)
</div>
<a href="https://github.com/roboflow/supervision/issues?q=is%3Aissue+label%3Ahacktoberfest+">
<img width="100%" src="https://media.roboflow.com/open-source/supervision/hacktoberfest-banner-3.png">
</a>
## 👋 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! 🤝
[![supervision-hackfest](https://github.com/roboflow/supervision/assets/26109316/c05cc954-b9a6-4ed5-9a52-d0b4b619ff65)](https://github.com/orgs/roboflow/projects/10)
## 💻 install
Pip install the supervision package in a
[**3.11>=Python>=3.8**](https://www.python.org/) environment.
[**Python>=3.8**](https://www.python.org/) environment.
```bash
pip install supervision[desktop]
pip install supervision
```
Read more about desktop, headless, and local installation in our [guide](https://roboflow.github.io/supervision/).
Read more about conda, mamba, and installing from source in our [guide](https://roboflow.github.io/supervision/).
## 🔥 quickstart
### [detections processing](https://roboflow.github.io/supervision/detection/core/)
### 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, or MMDetection.
```python
>>> import supervision as sv
>>> from ultralytics import YOLO
import cv2
import supervision as sv
from ultralytics import YOLO
>>> model = YOLO('yolov8s.pt')
>>> result = model(IMAGE)[0]
>>> detections = sv.Detections.from_ultralytics(result)
image = cv2.imread(...)
model = YOLO('yolov8s.pt')
result = model(image)[0]
detections = sv.Detections.from_ultralytics(result)
>>> len(detections)
5
len(detections)
# 5
```
<details close>
<summary>👉 more detections utils</summary>
<details>
<summary>👉 more model connectors</summary>
- Easily switch inference pipeline between supported object detection/instance segmentation models
- 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 segment_anything import sam_model_registry, SamAutomaticMaskGenerator
import cv2
import supervision as sv
from inference.models.utils import get_roboflow_model
>>> sam = sam_model_registry[MODEL_TYPE](checkpoint=CHECKPOINT_PATH).to(device=DEVICE)
>>> mask_generator = SamAutomaticMaskGenerator(sam)
>>> sam_result = mask_generator.generate(IMAGE)
>>> detections = sv.Detections.from_sam(sam_result=sam_result)
```
image = cv2.imread(...)
model = get_roboflow_model(model_id="yolov8s-640", api_key=<ROBOFLOW API KEY>)
result = model.infer(image)[0]
detections = sv.Detections.from_inference(result)
- [Advanced filtering](https://roboflow.github.io/supervision/quickstart/detections/)
len(detections)
# 5
```python
>>> detections = detections[detections.class_id == 0]
>>> detections = detections[detections.confidence > 0.5]
>>> detections = detections[detections.area > 1000]
```
- Image annotation
```python
>>> import supervision as sv
>>> box_annotator = sv.BoxAnnotator()
>>> annotated_frame = box_annotator.annotate(
... scene=IMAGE,
... detections=detections
... )
```
</details>
### [datasets processing](https://roboflow.github.io/supervision/dataset/core/)
### annotators
Supervision offers a wide range of highly customizable [annotators](https://supervision.roboflow.com/latest/annotators/), allowing you to compose the perfect visualization for your use case.
```python
>>> import supervision as sv
import cv2
import supervision as sv
>>> dataset = sv.DetectionDataset.from_yolo(
... images_directory_path='...',
... annotations_directory_path='...',
... data_yaml_path='...'
... )
image = cv2.imread(...)
detections = sv.Detections(...)
>>> dataset.classes
bounding_box_annotator = sv.BoundingBoxAnnotator()
annotated_frame = bounding_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/) that allow you to load, split, merge, and save datasets in one of the supported formats.
```python
import supervision as sv
dataset = sv.DetectionDataset.from_yolo(
images_directory_path=...,
annotations_directory_path=...,
data_yaml_path=...
)
dataset.classes
['dog', 'person']
>>> len(dataset)
1000
len(dataset)
# 1000
```
<details close>
<summary>👉 more dataset utils</summary>
- Load object detection/instance segmentation datasets in one of the supported formats
- load
```python
>>> dataset = sv.DetectionDataset.from_yolo(
... images_directory_path='...',
... annotations_directory_path='...',
... data_yaml_path='...'
... )
```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_pascal_voc(
images_directory_path=...,
annotations_directory_path=...
)
>>> dataset = sv.DetectionDataset.from_coco(
... images_directory_path='...',
... annotations_path='...'
... )
```
dataset = sv.DetectionDataset.from_coco(
images_directory_path=...,
annotations_path=...
)
```
- Loop over dataset entries
- split
```python
>>> for name, image, labels in dataset:
... print(labels.xyxy)
```python
train_dataset, test_dataset = dataset.split(split_ratio=0.7)
test_dataset, valid_dataset = test_dataset.split(split_ratio=0.5)
array([[404. , 719. , 538. , 884.5 ],
[155. , 497. , 404. , 833.5 ],
[ 20.154999, 347.825 , 416.125 , 915.895 ]], dtype=float32)
```
len(train_dataset), len(test_dataset), len(valid_dataset)
# (700, 150, 150)
```
- Split dataset for training, testing, and validation
- merge
```python
>>> train_dataset, test_dataset = dataset.split(split_ratio=0.7)
>>> test_dataset, valid_dataset = test_dataset.split(split_ratio=0.5)
```python
ds_1 = sv.DetectionDataset(...)
len(ds_1)
# 100
ds_1.classes
# ['dog', 'person']
>>> len(train_dataset), len(test_dataset), len(valid_dataset)
(700, 150, 150)
```
ds_2 = sv.DetectionDataset(...)
len(ds_2)
# 200
ds_2.classes
# ['cat']
- Merge multiple datasets
ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])
len(ds_merged)
# 300
ds_merged.classes
# ['cat', 'dog', 'person']
```
```python
>>> ds_1 = sv.DetectionDataset(...)
>>> len(ds_1)
100
>>> ds_1.classes
['dog', 'person']
- save
>>> ds_2 = sv.DetectionDataset(...)
>>> len(ds_2)
200
>>> ds_2.classes
['cat']
```python
dataset.as_yolo(
images_directory_path=...,
annotations_directory_path=...,
data_yaml_path=...
)
>>> ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])
>>> len(ds_merged)
300
>>> ds_merged.classes
['cat', 'dog', 'person']
```
dataset.as_pascal_voc(
images_directory_path=...,
annotations_directory_path=...
)
- Save object detection/instance segmentation datasets in one of the supported formats
dataset.as_coco(
images_directory_path=...,
annotations_path=...
)
```
```python
>>> dataset.as_yolo(
... images_directory_path='...',
... annotations_directory_path='...',
... data_yaml_path='...'
... )
- convert
>>> dataset.as_pascal_voc(
... images_directory_path='...',
... annotations_directory_path='...'
... )
>>> dataset.as_coco(
... images_directory_path='...',
... annotations_path='...'
... )
```
- Convert labels between supported formats
```python
>>> sv.DetectionDataset.from_yolo(
... images_directory_path='...',
... annotations_directory_path='...',
... data_yaml_path='...'
... ).as_pascal_voc(
... images_directory_path='...',
... annotations_directory_path='...'
... )
```
- Load classification datasets in one of the supported formats
```python
>>> cs = sv.ClassificationDataset.from_folder_structure(
... root_directory_path='...'
... )
```
- Save classification datasets in one of the supported formats
```python
>>> cs.as_folder_structure(
... root_directory_path='...'
... )
```
</details>
### [model evaluation](https://roboflow.github.io/supervision/metrics/detection/)
```python
>>> import supervision as sv
>>> dataset = sv.DetectionDataset.from_yolo(...)
>>> def callback(image: np.ndarray) -> sv.Detections:
... ...
>>> confusion_matrix = sv.ConfusionMatrix.benchmark(
... dataset = dataset,
... callback = callback
... )
>>> confusion_matrix.matrix
array([
[0., 0., 0., 0.],
[0., 1., 0., 1.],
[0., 1., 1., 0.],
[1., 1., 0., 0.]
])
```
<details close>
<summary>👉 more metrics</summary>
- Mean average precision (mAP) for object detection tasks.
```python
>>> import supervision as sv
>>> dataset = sv.DetectionDataset.from_yolo(...)
>>> def callback(image: np.ndarray) -> sv.Detections:
... ...
>>> mean_average_precision = sv.MeanAveragePrecision.benchmark(
... dataset = dataset,
... callback = callback
... )
>>> mean_average_precision.map50_95
0.433
```
```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
<p align="left">
<a href="https://youtu.be/4Q3ut7vqD5o" title="Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking"><img src="https://github.com/roboflow/supervision/assets/26109316/54afdf1c-218c-4451-8f12-627fb85f1682" alt="Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking" width="300px" align="left" /></a>
<a href="https://youtu.be/4Q3ut7vqD5o" title="Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking"><strong>Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking</strong></a>
<div><strong>Created: 6 Sep 2023</strong> | <strong>Updated: 6 Sep 2023</strong></div>
<br/> In this video, we explore real-time traffic analysis using YOLOv8 and ByteTrack to detect and track vehicles on aerial images. Harnessing the power of Python and Supervision, we delve deep into assigning cars to specific entry zones and understanding their direction of movement. By visualizing their paths, we gain insights into traffic flow across bustling roundabouts... </p>
<a href="https://youtu.be/uWP6UjDeZvY" title="Speed Estimation & Vehicle Tracking | Computer Vision | Open Source"><img src="https://github.com/SkalskiP/SkalskiP/assets/26109316/61a444c8-b135-48ce-b979-2a5ab47c5a91" 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> | <strong>Updated: 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>
<br/>
<p align="left">
<a href="https://youtu.be/D-D6ZmadzPE" title="SAM - Segment Anything Model by Meta AI: Complete Guide"><img src="https://github.com/SkalskiP/SkalskiP/assets/26109316/6913ff11-53c6-4341-8d90-eaff3023c3fd" alt="SAM - Segment Anything Model by Meta AI: Complete Guide" width="300px" align="left" /></a>
<a href="https://youtu.be/D-D6ZmadzPE" title="SAM - Segment Anything Model by Meta AI: Complete Guide"><strong>SAM - Segment Anything Model by Meta AI: Complete Guide</strong></a>
<div><strong>Created: 11 Apr 2023</strong> | <strong>Updated: 11 Apr 2023</strong></div>
<br/> Discover the incredible potential of Meta AI's Segment Anything Model (SAM)! We dive into SAM, an efficient and promptable model for image segmentation, which has revolutionized computer vision tasks. With over 1 billion masks on 11M licensed and privacy-respecting images, SAM's zero-shot performance is often competitive with or even superior to prior fully supervised results... </p>
<a href="https://youtu.be/4Q3ut7vqD5o" title="Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking"><img src="https://github.com/roboflow/supervision/assets/26109316/54afdf1c-218c-4451-8f12-627fb85f1682" alt="Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking" width="300px" align="left" /></a>
<a href="https://youtu.be/4Q3ut7vqD5o" title="Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking"><strong>Traffic Analysis with YOLOv8 and ByteTrack - Vehicle Detection and Tracking</strong></a>
<div><strong>Created: 6 Sep 2023</strong> | <strong>Updated: 6 Sep 2023</strong></div>
<br/> In this video, we explore real-time traffic analysis using YOLOv8 and ByteTrack to detect and track vehicles on aerial images. Harnessing the power of Python and Supervision, we delve deep into assigning cars to specific entry zones and understanding their direction of movement. By visualizing their paths, we gain insights into traffic flow across bustling roundabouts... </p>
## 💜 built with supervision
@@ -302,6 +239,8 @@ https://user-images.githubusercontent.com/26109316/207858600-ee862b22-0353-440b-
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.
@@ -363,5 +302,4 @@ We love your input! Please see our [contributing guide](https://github.com/robof
</a>
</a>
</div>
</div>
Vendored
+1342 -1322
View File
File diff suppressed because it is too large. Load diff
+367 -93
View File
@@ -1,16 +1,23 @@
---
comments: true
status: new
---
# Annotators
=== "BoundingBox"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> bounding_box_annotator = sv.BoundingBoxAnnotator()
>>> annotated_frame = bounding_box_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
bounding_box_annotator = sv.BoundingBoxAnnotator()
annotated_frame = bounding_box_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -19,19 +26,40 @@
</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
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> corner_annotator = sv.BoxCornerAnnotator()
>>> annotated_frame = corner_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
corner_annotator = sv.BoxCornerAnnotator()
annotated_frame = corner_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -40,19 +68,19 @@
</div>
=== "BoxMask"
=== "Color"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> box_mask_annotator = sv.BoxMaskAnnotator()
>>> annotated_frame = box_mask_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
color_annotator = sv.ColorAnnotator()
annotated_frame = color_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -64,16 +92,16 @@
=== "Circle"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> circle_annotator = sv.CircleAnnotator()
>>> annotated_frame = circle_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
circle_annotator = sv.CircleAnnotator()
annotated_frame = circle_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -82,19 +110,61 @@
</div>
=== "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>
=== "Ellipse"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> ellipse_annotator = sv.EllipseAnnotator()
>>> annotated_frame = ellipse_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
ellipse_annotator = sv.EllipseAnnotator()
annotated_frame = ellipse_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -106,37 +176,58 @@
=== "Halo"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> halo_annotator = sv.HaloAnnotator()
>>> annotated_frame = halo_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
halo_annotator = sv.HaloAnnotator()
annotated_frame = halo_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" }
![halo-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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>
=== "Mask"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> mask_annotator = sv.MaskAnnotator()
>>> annotated_frame = mask_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
mask_annotator = sv.MaskAnnotator()
annotated_frame = mask_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -145,19 +236,47 @@
</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>
=== "Label"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
>>> annotated_frame = label_annotator.annotate(
... scene=image.copy(),
... detections=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>
@@ -166,19 +285,34 @@
</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
)
```
=== "Blur"
```python
>>> import supervision as sv
import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
image = ...
detections = sv.Detections(...)
>>> blur_annotator = sv.BlurAnnotator()
>>> annotated_frame = blur_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
blur_annotator = sv.BlurAnnotator()
annotated_frame = blur_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
@@ -187,19 +321,50 @@
</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>
=== "Trace"
```python
>>> import supervision as sv
import supervision as sv
from ultralytics import YOLO
>>> image = ...
>>> detections = sv.Detections(...)
model = YOLO('yolov8x.pt')
>>> trace_annotator = sv.TraceAnnotator()
>>> annotated_frame = trace_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
trace_annotator = sv.TraceAnnotator()
video_info = sv.VideoInfo.from_video_path(video_path='...')
frames_generator = 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>
@@ -208,42 +373,151 @@
</div>
## BoundingBoxAnnotator
=== "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 = 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>
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.BoundingBoxAnnotator">BoundingBoxAnnotator</a></h2>
</div>
:::supervision.annotators.core.BoundingBoxAnnotator
## BoxCornerAnnotator
<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
## BoxMaskAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.OrientedBoxAnnotator">OrientedBoxAnnotator</a></h2>
</div>
:::supervision.annotators.core.BoxMaskAnnotator
:::supervision.annotators.core.OrientedBoxAnnotator
## CircleAnnotator
<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
## EllipseAnnotator
<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
## HaloAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.HaloAnnotator">HaloAnnotator</a></h2>
</div>
:::supervision.annotators.core.HaloAnnotator
## MaskAnnotator
<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
## LabelAnnotator
<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
## BlurAnnotator
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.BlurAnnotator">BlurAnnotator</a></h2>
</div>
:::supervision.annotators.core.BlurAnnotator
## TraceAnnotator
<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.ColorLookup">ColorLookup</a></h2>
</div>
:::supervision.annotators.utils.ColorLookup
+31
View File
@@ -0,0 +1,31 @@
---
comments: true
---
# Assets
Supervision offers an assets download utility that allows you to download video files
that you can use in your demos.
## Install extra
To install the Supervision assets utility, you can use `pip`. This utility is available
as an extra within the Supervision package.
!!! example "pip install"
```bash
pip install "supervision[assets]"
```
<div class="md-typeset">
<h2>download_assets</h2>
</div>
:::supervision.assets.downloader.download_assets
<div class="md-typeset">
<h2>VideoAssets</h2>
</div>
:::supervision.assets.list.VideoAssets
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+297 -46
View File
@@ -1,18 +1,269 @@
### 0.19.0 <small>March 15, 2024</small>
- Added [#818](https://github.com/roboflow/supervision/pull/818): [`sv.CSVSink`](/0.19.0/detection/tools/save_detections/#supervision.detection.tools.csv_sink.CSVSink) allowing for the straightforward saving of image, video, or stream inference results in a `.csv` file.
```python
import supervision as sv
from ultralytics import YOLO
model = YOLO(<SOURCE_MODEL_PATH>)
csv_sink = sv.CSVSink(<RESULT_CSV_FILE_PATH>)
frames_generator = sv.get_video_frames_generator(<SOURCE_VIDEO_PATH>)
with csv_sink:
for frame in frames_generator:
result = model(frame)[0]
detections = sv.Detections.from_ultralytics(result)
csv_sink.append(detections, custom_data={<CUSTOM_LABEL>:<CUSTOM_DATA>})
```
- Added [#819](https://github.com/roboflow/supervision/pull/819): [`sv.JSONSink`](/0.19.0/detection/tools/save_detections/#supervision.detection.tools.csv_sink.JSONSink) allowing for the straightforward saving of image, video, or stream inference results in a `.json` file.
```python
```python
import supervision as sv
from ultralytics import YOLO
model = YOLO(<SOURCE_MODEL_PATH>)
json_sink = sv.JSONSink(<RESULT_JSON_FILE_PATH>)
frames_generator = sv.get_video_frames_generator(<SOURCE_VIDEO_PATH>)
with json_sink:
for frame in frames_generator:
result = model(frame)[0]
detections = sv.Detections.from_ultralytics(result)
json_sink.append(detections, custom_data={<CUSTOM_LABEL>:<CUSTOM_DATA>})
```
- Added [#847](https://github.com/roboflow/supervision/pull/847): [`sv.mask_iou_batch`](/0.19.0/detection/utils/#supervision.detection.utils.mask_iou_batch) allowing to compute Intersection over Union (IoU) of two sets of masks.
- Added [#847](https://github.com/roboflow/supervision/pull/847): [`sv.mask_non_max_suppression`](/0.19.0/detection/utils/#supervision.detection.utils.mask_non_max_suppression) allowing to perform Non-Maximum Suppression (NMS) on segmentation predictions.
- Added [#888](https://github.com/roboflow/supervision/pull/888): [`sv.CropAnnotator`](/0.19.0/annotators/#supervision.annotators.core.CropAnnotator) allowing users to annotate the scene with scaled-up crops of detections.
```python
import cv2
import supervision as sv
from inference import get_model
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = get_model(model_id="yolov8n-640")
result = model.infer(image)[0]
detections = sv.Detections.from_inference(result)
crop_annotator = sv.CropAnnotator()
annotated_frame = crop_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
- Changed [#827](https://github.com/roboflow/supervision/pull/827): [`sv.ByteTrack.reset`](/0.19.0/tracking/#supervision.tracking.ByteTrack.reset) allowing users to clear trackers state, enabling the processing of multiple video files in sequence.
- Changed [#802](https://github.com/roboflow/supervision/pull/802): [`sv.LineZoneAnnotator`](/0.19.0/detection/tools/line_zone/#supervision.detection.line_zone.LineZone) allowing to hide in/out count using `display_in_count` and `display_out_count` properties.
- Changed [#787](https://github.com/roboflow/supervision/pull/787): [`sv.ByteTrack`](/0.19.0/tracking/#supervision.tracking.ByteTrack) input arguments and docstrings updated to improve readability and ease of use.
!!! failure "Deprecated"
The `track_buffer`, `track_thresh`, and `match_thresh` parameters in `sv.ByterTrack` are deprecated and will be removed in `supervision-0.23.0`. Use `lost_track_buffer,` `track_activation_threshold`, and `minimum_matching_threshold` instead.
- Changed [#910](https://github.com/roboflow/supervision/pull/910): [`sv.PolygonZone`](/0.19.0/detection/tools/polygon_zone/#supervision.detection.tools.polygon_zone.PolygonZone) to now accept a list of specific box anchors that must be in zone for a detection to be counted.
!!! failure "Deprecated"
The `triggering_position ` parameter in `sv.PolygonZone` is deprecated and will be removed in `supervision-0.23.0`. Use `triggering_anchors` instead.
- Changed [#875](https://github.com/roboflow/supervision/pull/875): annotators adding support for Pillow images. All supervision Annotators can now accept an image as either a numpy array or a Pillow Image. They automatically detect its type, draw annotations, and return the output in the same format as the input.
- Fixed [#944](https://github.com/roboflow/supervision/pull/944): [`sv.DetectionsSmoother`](/0.19.0/detection/tools/smoother/#supervision.detection.tools.smoother.DetectionsSmoother) removing `tracking_id` from `sv.Detections`.
### 0.18.0 <small>January 25, 2024</small>
- Added [#720](https://github.com/roboflow/supervision/pull/720): [`sv.PercentageBarAnnotator`](/0.18.0/annotators/#percentagebarannotator) allowing to annotate images and videos with percentage values representing confidence or other custom property.
```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
... )
```
- Added [#702](https://github.com/roboflow/supervision/pull/702): [`sv.RoundBoxAnnotator`](/0.18.0/annotators/#roundboxannotator) allowing to annotate images and videos with rounded corners bounding boxes.
- Added [#770](https://github.com/roboflow/supervision/pull/770): [`sv.OrientedBoxAnnotator`](/0.18.0/annotators/#orientedboxannotator) allowing to annotate images and videos with OBB (Oriented Bounding Boxes).
```python
import cv2
import supervision as sv
from ultralytics import YOLO
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = YOLO("yolov8n-obb.pt")
result = model(image)[0]
detections = sv.Detections.from_ultralytics(result)
oriented_box_annotator = sv.OrientedBoxAnnotator()
annotated_frame = oriented_box_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
- Added [#696](https://github.com/roboflow/supervision/pull/696): [`sv.DetectionsSmoother`](/0.18.0/detection/tools/smoother/#detection-smoother) allowing for smoothing detections over multiple frames in video tracking.
- Added [#769](https://github.com/roboflow/supervision/pull/769): [`sv.ColorPalette.from_matplotlib`](/0.18.0/draw/color/#supervision.draw.color.ColorPalette.from_matplotlib) allowing users to create a `sv.ColorPalette` instance from a Matplotlib color palette.
```python
>>> import supervision as sv
>>> sv.ColorPalette.from_matplotlib('viridis', 5)
ColorPalette(colors=[Color(r=68, g=1, b=84), Color(r=59, g=82, b=139), ...])
```
- Changed [#770](https://github.com/roboflow/supervision/pull/770): [`sv.Detections.from_ultralytics`](/0.18.0/detection/core/#supervision.detection.core.Detections.from_ultralytics) adding support for OBB (Oriented Bounding Boxes).
- Changed [#735](https://github.com/roboflow/supervision/pull/735): [`sv.LineZone`](/0.18.0/detection/tools/line_zone/#linezone) to now accept a list of specific box anchors that must cross the line for a detection to be counted. This update marks a significant improvement from the previous requirement, where all four box corners were necessary. Users can now specify a single anchor, such as `sv.Position.BOTTOM_CENTER`, or any other combination of anchors defined as `List[sv.Position]`.
- Changed [#756](https://github.com/roboflow/supervision/pull/756): [`sv.Color`](/0.18.0/draw/color/#color)'s and [`sv.ColorPalette`](/0.18.0/draw/color/#colorpalette)'s method of accessing predefined colors, transitioning from a function-based approach (`sv.Color.red()`) to a more intuitive and conventional property-based method (`sv.Color.RED`).
!!! failure "Deprecated"
`sv.ColorPalette.default()` is deprecated and will be removed in `supervision-0.22.0`. Use `sv.ColorPalette.DEFAULT` instead.
- Changed [#769](https://github.com/roboflow/supervision/pull/769): [`sv.ColorPalette.DEFAULT`](/0.18.0/draw/color/#colorpalette) value, giving users a more extensive set of annotation colors.
- Changed [#677](https://github.com/roboflow/supervision/pull/677): `sv.Detections.from_roboflow` to [`sv.Detections.from_inference`](/0.18.0/detection/core/#supervision.detection.core.Detections.from_inference) streamlining its functionality to be compatible with both the both [inference](https://github.com/roboflow/inference) pip package and the Robloflow [hosted API](https://docs.roboflow.com/deploy/hosted-api).
!!! failure "Deprecated"
`Detections.from_roboflow()` is deprecated and will be removed in `supervision-0.22.0`. Use `Detections.from_inference` instead.
- Fixed [#735](https://github.com/roboflow/supervision/pull/735): [`sv.LineZone`](/0.18.0/detection/tools/line_zone/#linezone) functionality to accurately update the counter when an object crosses a line from any direction, including from the side. This enhancement enables more precise tracking and analytics, such as calculating individual in/out counts for each lane on the road.
### 0.17.0 <small>December 06, 2023</small>
- Added [#633](https://github.com/roboflow/supervision/pull/633): [`sv.PixelateAnnotator`](/0.17.0/annotators/#supervision.annotators.core.PixelateAnnotator) allowing to pixelate objects on images and videos.
- Added [#652](https://github.com/roboflow/supervision/pull/652): [`sv.TriangleAnnotator`](/0.17.0/annotators/#supervision.annotators.core.TriangleAnnotator) allowing to annotate images and videos with triangle markers.
- Added [#602](https://github.com/roboflow/supervision/pull/602): [`sv.PolygonAnnotator`](/0.17.0/annotators/#supervision.annotators.core.PolygonAnnotator) allowing to annotate images and videos with segmentation mask outline.
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> polygon_annotator = sv.PolygonAnnotator()
>>> annotated_frame = polygon_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
- Added [#476](https://github.com/roboflow/supervision/pull/476): [`sv.assets`](/0.18.0/assets/) allowing download of video files that you can use in your demos.
```python
>>> from supervision.assets import download_assets, VideoAssets
>>> download_assets(VideoAssets.VEHICLES)
"vehicles.mp4"
```
- Added [#605](https://github.com/roboflow/supervision/pull/605): [`Position.CENTER_OF_MASS`](/0.17.0/geometry/core/#position) allowing to place labels in center of mass of segmentation masks.
- Added [#651](https://github.com/roboflow/supervision/pull/651): [`sv.scale_boxes`](/0.17.0/detection/utils/#supervision.detection.utils.scale_boxes) allowing to scale [`sv.Detections.xyxy`](/0.17.0/detection/core/#supervision.detection.core.Detections) values.
- Added [#637](https://github.com/roboflow/supervision/pull/637): [`sv.calculate_dynamic_text_scale`](/0.17.0/draw/utils/#supervision.draw.utils.calculate_dynamic_text_scale) and [`sv.calculate_dynamic_line_thickness`](/0.17.0/draw/utils/#supervision.draw.utils.calculate_dynamic_line_thickness) allowing text scale and line thickness to match image resolution.
- Added [#620](https://github.com/roboflow/supervision/pull/620): [`sv.Color.as_hex`](/0.17.0/draw/color/#supervision.draw.color.Color.as_hex) allowing to extract color value in HEX format.
- Added [#572](https://github.com/roboflow/supervision/pull/572): [`sv.Classifications.from_timm`](/0.17.0/classification/core/#supervision.classification.core.Classifications.from_timm) allowing to load classification result from [timm](https://huggingface.co/docs/hub/timm) models.
- Added [#478](https://github.com/roboflow/supervision/pull/478): [`sv.Classifications.from_clip`](/0.17.0/classification/core/#supervision.classification.core.Classifications.from_clip) allowing to load classification result from [clip](https://github.com/openai/clip) model.
- Added [#571](https://github.com/roboflow/supervision/pull/571): [`sv.Detections.from_azure_analyze_image`](/0.17.0/detection/core/#supervision.detection.core.Detections.from_azure_analyze_image) allowing to load detection results from [Azure Image Analysis](https://learn.microsoft.com/en-us/azure/ai-services/computer-vision/concept-object-detection-40).
- Changed [#646](https://github.com/roboflow/supervision/pull/646): `sv.BoxMaskAnnotator` renaming it to [`sv.ColorAnnotator`](/0.17.0/annotators/#supervision.annotators.core.ColorAnnotator).
- Changed [#606](https://github.com/roboflow/supervision/pull/606): [`sv.MaskAnnotator`](/0.17.0/annotators/#supervision.annotators.core.MaskAnnotator) to make it **5x faster**.
- Fixed [#584](https://github.com/roboflow/supervision/pull/584): [`sv.DetectionDataset.from_yolo`](/0.17.0/datasets/#supervision.dataset.core.DetectionDataset.from_yolo) to ignore empty lines in annotation files.
- Fixed [#555](https://github.com/roboflow/supervision/pull/555): [`sv.BlurAnnotator`](/0.17.0/annotators/#supervision.annotators.core.BlurAnnotator) to trim negative coordinates before bluring detections.
- Fixed [#511](https://github.com/roboflow/supervision/pull/511): [`sv.TraceAnnotator`](/0.17.0/annotators/#supervision.annotators.core.TraceAnnotator) to respect trace position.
### 0.16.0 <small>October 19, 2023</small>
- Added [#422](https://github.com/roboflow/supervision/pull/422): [`sv.BoxMaskAnnotator`](/0.16.0/annotators/#supervision.annotators.core.BoxMaskAnnotator) allowing to annotate images and videos with mox masks.
- Added [#433](https://github.com/roboflow/supervision/pull/433): [`sv.HaloAnnotator`](/0.16.0/annotators/#supervision.annotators.core.HaloAnnotator) allowing to annotate images and videos with halo effect.
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> halo_annotator = sv.HaloAnnotator()
>>> annotated_frame = halo_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
- Added [#466](https://github.com/roboflow/supervision/pull/466): [`sv.HeatMapAnnotator`](/0.16.0/annotators/#supervision.annotators.core.HeatMapAnnotator) allowing to annotate videos with heat maps.
- Added [#492](https://github.com/roboflow/supervision/pull/492): [`sv.DotAnnotator`](/0.16.0/annotators/#supervision.annotators.core.DotAnnotator) allowing to annotate images and videos with dots.
- Added [#449](https://github.com/roboflow/supervision/pull/449): [`sv.draw_image`](/0.16.0/draw/utils/#supervision.draw.utils.draw_image) allowing to draw an image onto a given scene with specified opacity and dimensions.
- Added [#280](https://github.com/roboflow/supervision/pull/280): [`sv.FPSMonitor`](/0.16.0/utils/video/#supervision.utils.video.FPSMonitor) for monitoring frames per second (FPS) to benchmark latency.
- Added [#454](https://github.com/roboflow/supervision/pull/454): 🤗 Hugging Face Annotators [space](https://huggingface.co/spaces/Roboflow/Annotators).
- Changed [#482](https://github.com/roboflow/supervision/pull/482): [`sv.LineZone.trigger`](/0.16.0/detection/tools/line_zone/#supervision.detection.line_counter.LineZone.trigger) now return `Tuple[np.ndarray, np.ndarray]`. The first array indicates which detections have crossed the line from outside to inside. The second array indicates which detections have crossed the line from inside to outside.
- Changed [#465](https://github.com/roboflow/supervision/pull/465): Annotator argument name from `color_map: str` to `color_lookup: ColorLookup` enum to increase type safety.
- Changed [#426](https://github.com/roboflow/supervision/pull/426): [`sv.MaskAnnotator`](/0.16.0/annotators/#supervision.annotators.core.MaskAnnotator) allowing 2x faster annotation.
- Fixed [#477](https://github.com/roboflow/supervision/pull/477): Poetry env definition allowing proper local installation.
- Fixed [#430](https://github.com/roboflow/supervision/pull/430): [`sv.ByteTrack`](/0.16.0/trackers/#supervision.tracker.byte_tracker.core.ByteTrack) to return `np.array([], dtype=int)` when `svDetections` is empty.
!!! failure "Deprecated"
`sv.Detections.from_yolov8` and `sv.Classifications.from_yolov8` as those are now replaced by [`sv.Detections.from_ultralytics`](/0.16.0/detection/core/#supervision.detection.core.Detections.from_ultralytics) and [`sv.Classifications.from_ultralytics`](/0.16.0/classification/core/#supervision.classification.core.Classifications.from_ultralytics).
### 0.15.0 <small>October 5, 2023</small>
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.BoundingBoxAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BoundingBoxAnnotator) allowing to annotate images and videos with bounding boxes.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.BoundingBoxAnnotator`](/0.15.0/annotators/#supervision.annotators.core.BoundingBoxAnnotator) allowing to annotate images and videos with bounding boxes.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.BoxCornerAnnotator `](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BoxCornerAnnotator) allowing to annotate images and videos with just bounding box corners.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.BoxCornerAnnotator `](/0.15.0/annotators/#supervision.annotators.core.BoxCornerAnnotator) allowing to annotate images and videos with just bounding box corners.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.MaskAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.MaskAnnotator) allowing to annotate images and videos with segmentation masks.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.MaskAnnotator`](/0.15.0/annotators/#supervision.annotators.core.MaskAnnotator) allowing to annotate images and videos with segmentation masks.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.EllipseAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.EllipseAnnotator) allowing to annotate images and videos with ellipses (sports game style).
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.EllipseAnnotator`](/0.15.0/annotators/#supervision.annotators.core.EllipseAnnotator) allowing to annotate images and videos with ellipses (sports game style).
- Added [#386](https://github.com/roboflow/supervision/pull/386): [`sv.CircleAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.CircleAnnotator) allowing to annotate images and videos with circles.
- Added [#386](https://github.com/roboflow/supervision/pull/386): [`sv.CircleAnnotator`](/0.15.0/annotators/#supervision.annotators.core.CircleAnnotator) allowing to annotate images and videos with circles.
- Added [#354](https://github.com/roboflow/supervision/pull/354): [`sv.TraceAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.TraceAnnotator) allowing to draw path of moving objects on videos.
- Added [#354](https://github.com/roboflow/supervision/pull/354): [`sv.TraceAnnotator`](/0.15.0/annotators/#supervision.annotators.core.TraceAnnotator) allowing to draw path of moving objects on videos.
- Added [#405](https://github.com/roboflow/supervision/pull/405): [`sv.BlurAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BlurAnnotator) allowing to blur objects on images and videos.
- Added [#405](https://github.com/roboflow/supervision/pull/405): [`sv.BlurAnnotator`](/0.15.0/annotators/#supervision.annotators.core.BlurAnnotator) allowing to blur objects on images and videos.
```python
>>> import supervision as sv
@@ -29,17 +280,17 @@
- Added [#354](https://github.com/roboflow/supervision/pull/354): Supervision usage [example](https://github.com/roboflow/supervision/tree/develop/examples/traffic_analysis). You can now learn how to perform traffic flow analysis with Supervision.
- Changed [#399](https://github.com/roboflow/supervision/pull/399): [`sv.Detections.from_roboflow`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_roboflow) now does not require `class_list` to be specified. The `class_id` value can be extracted directly from the [inference](https://github.com/roboflow/inference) response.
- Changed [#399](https://github.com/roboflow/supervision/pull/399): [`sv.Detections.from_roboflow`](/0.15.0/detection/core/#supervision.detection.core.Detections.from_roboflow) now does not require `class_list` to be specified. The `class_id` value can be extracted directly from the [inference](https://github.com/roboflow/inference) response.
- Changed [#381](https://github.com/roboflow/supervision/pull/381): [`sv.VideoSink`](https://supervision.roboflow.com/utils/video/#videosink) now allows to customize the output codec.
- Changed [#381](https://github.com/roboflow/supervision/pull/381): [`sv.VideoSink`](/0.15.0/utils/video/#videosink) now allows to customize the output codec.
- Changed [#361](https://github.com/roboflow/supervision/pull/361): [`sv.InferenceSlicer`](https://supervision.roboflow.com/detection/tools/inference_slicer/#supervision.detection.tools.inference_slicer.InferenceSlicer) can now operate in multithreading mode.
- Changed [#361](https://github.com/roboflow/supervision/pull/361): [`sv.InferenceSlicer`](/0.15.0/detection/tools/inference_slicer/#supervision.detection.tools.inference_slicer.InferenceSlicer) can now operate in multithreading mode.
- Fixed [#348](https://github.com/roboflow/supervision/pull/348): [`sv.Detections.from_deepsparse`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_deepsparse) to allow processing empty [deepsparse](https://github.com/neuralmagic/deepsparse) result object.
- Fixed [#348](https://github.com/roboflow/supervision/pull/348): [`sv.Detections.from_deepsparse`](/0.15.0/detection/core/#supervision.detection.core.Detections.from_deepsparse) to allow processing empty [deepsparse](https://github.com/neuralmagic/deepsparse) result object.
### 0.14.0 <small>August 31, 2023</small>
- Added [#282](https://github.com/roboflow/supervision/pull/282): support for SAHI inference technique with [`sv.InferenceSlicer`](https://supervision.roboflow.com/detection/tools/inference_slicer).
- Added [#282](https://github.com/roboflow/supervision/pull/282): support for SAHI inference technique with [`sv.InferenceSlicer`](/0.14.0/detection/tools/inference_slicer).
```python
>>> import cv2
@@ -58,23 +309,23 @@
>>> detections = slicer(image)
```
- Added [#297](https://github.com/roboflow/supervision/pull/297): [`Detections.from_deepsparse`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_deepsparse) to enable seamless integration with [DeepSparse](https://github.com/neuralmagic/deepsparse) framework.
- Added [#297](https://github.com/roboflow/supervision/pull/297): [`Detections.from_deepsparse`](/0.14.0/detection/core/#supervision.detection.core.Detections.from_deepsparse) to enable seamless integration with [DeepSparse](https://github.com/neuralmagic/deepsparse) framework.
- Added [#281](https://github.com/roboflow/supervision/pull/281): [`sv.Classifications.from_ultralytics`](https://supervision.roboflow.com/classification/core/#supervision.classification.core.Classifications.from_ultralytics) to enable seamless integration with [Ultralytics](https://github.com/ultralytics/ultralytics) framework. This will enable you to use supervision with all [models](https://docs.ultralytics.com/models/) that Ultralytics supports.
- Added [#281](https://github.com/roboflow/supervision/pull/281): [`sv.Classifications.from_ultralytics`](/0.14.0/classification/core/#supervision.classification.core.Classifications.from_ultralytics) to enable seamless integration with [Ultralytics](https://github.com/ultralytics/ultralytics) framework. This will enable you to use supervision with all [models](https://docs.ultralytics.com/models/) that Ultralytics supports.
!!! warning
!!! failure "Deprecated"
[sv.Detections.from_yolov8](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_yolov8) and [sv.Classifications.from_yolov8](https://supervision.roboflow.com/classification/core/#supervision.classification.core.Classifications.from_yolov8) are now deprecated and will be removed with supervision-0.16.0 release.
[sv.Detections.from_yolov8](/0.14.0/detection/core/#supervision.detection.core.Detections.from_yolov8) and [sv.Classifications.from_yolov8](/0.14.0/classification/core/#supervision.classification.core.Classifications.from_yolov8) are now deprecated and will be removed with `supervision-0.16.0` release.
- Added [#341](https://github.com/roboflow/supervision/pull/341): First supervision usage example script showing how to detect and track objects on video using YOLOv8 + Supervision.
- Changed [#296](https://github.com/roboflow/supervision/pull/296): [`sv.ClassificationDataset`](https://supervision.roboflow.com/dataset/core/#supervision.dataset.core.ClassificationDataset) and [`sv.DetectionDataset`](https://supervision.roboflow.com/dataset/core/#supervision.dataset.core.DetectionDataset) now use image path (not image name) as dataset keys.
- Changed [#296](https://github.com/roboflow/supervision/pull/296): [`sv.ClassificationDataset`](/0.14.0/dataset/core/#supervision.dataset.core.ClassificationDataset) and [`sv.DetectionDataset`](/0.14.0/dataset/core/#supervision.dataset.core.DetectionDataset) now use image path (not image name) as dataset keys.
- Fixed [#300](https://github.com/roboflow/supervision/pull/300): [`Detections.from_roboflow`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_roboflow) to filter out polygons with less than 3 points.
- Fixed [#300](https://github.com/roboflow/supervision/pull/300): [`Detections.from_roboflow`](/0.14.0/detection/core/#supervision.detection.core.Detections.from_roboflow) to filter out polygons with less than 3 points.
### 0.13.0 <small>August 8, 2023</small>
- Added [#236](https://github.com/roboflow/supervision/pull/236): support for mean average precision (mAP) for object detection models with [`sv.MeanAveragePrecision`](https://roboflow.github.io/supervision/metrics/detection/#meanaverageprecision).
- Added [#236](https://github.com/roboflow/supervision/pull/236): support for mean average precision (mAP) for object detection models with [`sv.MeanAveragePrecision`](/0.13.0/metrics/detection/#meanaverageprecision).
```python
>>> import supervision as sv
@@ -96,25 +347,25 @@
0.433
```
- Added [#256](https://github.com/roboflow/supervision/pull/256): support for ByteTrack for object tracking with [`sv.ByteTrack`](https://roboflow.github.io/supervision/tracker/core/#bytetrack).
- Added [#256](https://github.com/roboflow/supervision/pull/256): support for ByteTrack for object tracking with [`sv.ByteTrack`](/0.13.0/tracker/core/#bytetrack).
- Added [#222](https://github.com/roboflow/supervision/pull/222): [`sv.Detections.from_ultralytics`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_ultralytics) to enable seamless integration with [Ultralytics](https://github.com/ultralytics/ultralytics) framework. This will enable you to use `supervision` with all [models](https://docs.ultralytics.com/models/) that Ultralytics supports.
- Added [#222](https://github.com/roboflow/supervision/pull/222): [`sv.Detections.from_ultralytics`](/0.13.0/detection/core/#supervision.detection.core.Detections.from_ultralytics) to enable seamless integration with [Ultralytics](https://github.com/ultralytics/ultralytics) framework. This will enable you to use `supervision` with all [models](https://docs.ultralytics.com/models/) that Ultralytics supports.
!!! warning
!!! failure "Deprecated"
[`sv.Detections.from_yolov8`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_yolov8) is now deprecated and will be removed with `supervision-0.15.0` release.
[`sv.Detections.from_yolov8`](/0.13.0/detection/core/#supervision.detection.core.Detections.from_yolov8) is now deprecated and will be removed with `supervision-0.15.0` release.
- Added [#191](https://github.com/roboflow/supervision/pull/191): [`sv.Detections.from_paddledet`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_paddledet) to enable seamless integration with [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection) framework.
- Added [#191](https://github.com/roboflow/supervision/pull/191): [`sv.Detections.from_paddledet`](/0.13.0/detection/core/#supervision.detection.core.Detections.from_paddledet) to enable seamless integration with [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection) framework.
- Added [#245](https://github.com/roboflow/supervision/pull/245): support for loading PASCAL VOC segmentation datasets with [`sv.DetectionDataset.`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.from_pascal_voc).
- Added [#245](https://github.com/roboflow/supervision/pull/245): support for loading PASCAL VOC segmentation datasets with [`sv.DetectionDataset.`](/0.13.0/dataset/core/#supervision.dataset.core.DetectionDataset.from_pascal_voc).
### 0.12.0 <small>July 24, 2023</small>
!!! warning
!!! failure "Python 3.7. Support Terminated"
With the `supervision-0.12.0` release, we are terminating official support for Python 3.7.
- Added [#177](https://github.com/roboflow/supervision/pull/177): initial support for object detection model benchmarking with [`sv.ConfusionMatrix`](https://roboflow.github.io/supervision/metrics/detection/#confusionmatrix).
- Added [#177](https://github.com/roboflow/supervision/pull/177): initial support for object detection model benchmarking with [`sv.ConfusionMatrix`](/0.12.0/metrics/detection/#confusionmatrix).
```python
>>> import supervision as sv
@@ -141,23 +392,23 @@ array([
])
```
- Added [#173](https://github.com/roboflow/supervision/pull/173): [`Detections.from_mmdetection`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_mmdetection) to enable seamless integration with [MMDetection](https://github.com/open-mmlab/mmdetection) framework.
- Added [#173](https://github.com/roboflow/supervision/pull/173): [`Detections.from_mmdetection`](/0.12.0/detection/core/#supervision.detection.core.Detections.from_mmdetection) to enable seamless integration with [MMDetection](https://github.com/open-mmlab/mmdetection) framework.
- Added [#130](https://github.com/roboflow/supervision/issues/130): ability to [install](https://roboflow.github.io/supervision/) package in `headless` or `desktop` mode.
- Added [#130](https://github.com/roboflow/supervision/issues/130): ability to [install](https://supervision.roboflow.com/) package in `headless` or `desktop` mode.
- Changed [#180](https://github.com/roboflow/supervision/pull/180): packing method from `setup.py` to `pyproject.toml`.
- Fixed [#188](https://github.com/roboflow/supervision/issues/188): [`sv.DetectionDataset.from_cooc`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.from_coco) can't be loaded when there are images without annotations.
- Fixed [#188](https://github.com/roboflow/supervision/issues/188): [`sv.DetectionDataset.from_cooc`](/0.12.0/dataset/core/#supervision.dataset.core.DetectionDataset.from_coco) can't be loaded when there are images without annotations.
- Fixed [#226](https://github.com/roboflow/supervision/issues/226): [`sv.DetectionDataset.from_yolo`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.from_yolo) can't load background instances.
- Fixed [#226](https://github.com/roboflow/supervision/issues/226): [`sv.DetectionDataset.from_yolo`](/0.12.0/dataset/core/#supervision.dataset.core.DetectionDataset.from_yolo) can't load background instances.
### 0.11.1 <small>June 29, 2023</small>
- Fix [#165](https://github.com/roboflow/supervision/pull/165): [`as_folder_structure`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.ClassificationDataset.as_folder_structure) fails to save [`sv.ClassificationDataset`](https://roboflow.github.io/supervision/dataset/core/#classificationdataset) when it is result of inference.
- Fix [#165](https://github.com/roboflow/supervision/pull/165): [`as_folder_structure`](/0.11.1/dataset/core/#supervision.dataset.core.ClassificationDataset.as_folder_structure) fails to save [`sv.ClassificationDataset`](/0.11.1/dataset/core/#classificationdataset) when it is result of inference.
### 0.11.0 <small>June 28, 2023</small>
- Added [#150](https://github.com/roboflow/supervision/pull/150): ability to load and save [`sv.DetectionDataset`](https://roboflow.github.io/supervision/dataset/core/#detectiondataset) in COCO format using [`as_coco`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.as_coco) and [`from_coco`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.from_coco) methods.
- Added [#150](https://github.com/roboflow/supervision/pull/150): ability to load and save [`sv.DetectionDataset`](/0.11.0/dataset/core/#detectiondataset) in COCO format using [`as_coco`](/0.11.0/dataset/core/#supervision.dataset.core.DetectionDataset.as_coco) and [`from_coco`](/0.11.0/dataset/core/#supervision.dataset.core.DetectionDataset.from_coco) methods.
```python
>>> import supervision as sv
@@ -173,7 +424,7 @@ array([
... )
```
- Added [#158](https://github.com/roboflow/supervision/pull/158): ability to marge multiple [`sv.DetectionDataset`](https://roboflow.github.io/supervision/dataset/core/#detectiondataset) together using [`merge`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.merge) method.
- Added [#158](https://github.com/roboflow/supervision/pull/158): ability to merge multiple [`sv.DetectionDataset`](/0.11.0/dataset/core/#detectiondataset) together using [`merge`](/0.11.0/dataset/core/#supervision.dataset.core.DetectionDataset.merge) method.
```python
>>> import supervision as sv
@@ -197,13 +448,13 @@ array([
['cat', 'dog', 'person']
```
- Added [#162](https://github.com/roboflow/supervision/pull/162): additional `start` and `end` arguments to [`sv.get_video_frames_generator`](https://roboflow.github.io/supervision/utils/video/#get_video_frames_generator) allowing to generate frames only for a selected part of the video.
- Added [#162](https://github.com/roboflow/supervision/pull/162): additional `start` and `end` arguments to [`sv.get_video_frames_generator`](/0.11.0/utils/video/#get_video_frames_generator) allowing to generate frames only for a selected part of the video.
- Fix [#157](https://github.com/roboflow/supervision/pull/157): incorrect loading of YOLO dataset class names from `data.yaml`.
### 0.10.0 <small>June 14, 2023</small>
- Added [#125](https://github.com/roboflow/supervision/pull/125): ability to load and save [`sv.ClassificationDataset`](https://roboflow.github.io/supervision/dataset/core/#classificationdataset) in a folder structure format.
- Added [#125](https://github.com/roboflow/supervision/pull/125): ability to load and save [`sv.ClassificationDataset`](/0.10.0/dataset/core/#classificationdataset) in a folder structure format.
```python
>>> import supervision as sv
@@ -217,9 +468,9 @@ array([
... )
```
- Added [#125](https://github.com/roboflow/supervision/pull/125): support for [`sv.ClassificationDataset.split`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.ClassificationDataset.split) allowing to divide `sv.ClassificationDataset` into two parts.
- Added [#125](https://github.com/roboflow/supervision/pull/125): support for [`sv.ClassificationDataset.split`](/0.10.0/dataset/core/#supervision.dataset.core.ClassificationDataset.split) allowing to divide `sv.ClassificationDataset` into two parts.
- Added [#110](https://github.com/roboflow/supervision/pull/110): ability to extract masks from Roboflow API results using [`sv.Detections.from_roboflow`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_roboflow).
- Added [#110](https://github.com/roboflow/supervision/pull/110): ability to extract masks from Roboflow API results using [`sv.Detections.from_roboflow`](/0.10.0/detection/core/#supervision.detection.core.Detections.from_roboflow).
- Added [commit hash](https://github.com/roboflow/supervision/commit/d000292eb2f2342544e0947b65528082e60fb8d6): Supervision Quickstart [notebook](https://colab.research.google.com/github/roboflow/supervision/blob/main/demo.ipynb) where you can learn more about Detection, Dataset and Video APIs.
@@ -227,7 +478,7 @@ array([
### 0.9.0 <small>June 7, 2023</small>
- Added [#118](https://github.com/roboflow/supervision/pull/118): ability to select [`sv.Detections`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.__getitem__) by index, list of indexes or slice. Here is an example illustrating the new selection methods.
- Added [#118](https://github.com/roboflow/supervision/pull/118): ability to select [`sv.Detections`](/0.9.0/detection/core/#supervision.detection.core.Detections.__getitem__) by index, list of indexes or slice. Here is an example illustrating the new selection methods.
```python
>>> import supervision as sv
@@ -241,11 +492,11 @@ array([
2
```
- Added [#101](https://github.com/roboflow/supervision/pull/101): ability to extract masks from YOLOv8 result using [`sv.Detections.from_yolov8`](https://roboflow.github.io/supervision/detection/core/#supervision.detection.core.Detections.from_yolov8). Here is an example illustrating how to extract boolean masks from the result of the YOLOv8 model inference.
- Added [#101](https://github.com/roboflow/supervision/pull/101): ability to extract masks from YOLOv8 result using [`sv.Detections.from_yolov8`](/0.8.0/detection/core/#supervision.detection.core.Detections.from_yolov8). Here is an example illustrating how to extract boolean masks from the result of the YOLOv8 model inference.
- Added [#122](https://github.com/roboflow/supervision/pull/122): ability to crop image using [`sv.crop`](https://roboflow.github.io/supervision/utils/image/#crop). Here is an example showing how to get a separate crop for each detection in `sv.Detections`.
- Added [#122](https://github.com/roboflow/supervision/pull/122): ability to crop image using [`sv.crop`](/latest/utils/image/#crop). Here is an example showing how to get a separate crop for each detection in `sv.Detections`.
- Added [#120](https://github.com/roboflow/supervision/pull/120): ability to conveniently save multiple images into directory using [`sv.ImageSink`](https://roboflow.github.io/supervision/utils/image/#imagesink). Here is an example showing how to save every tenth video frame as a separate image.
- Added [#120](https://github.com/roboflow/supervision/pull/120): ability to conveniently save multiple images into directory using [`sv.ImageSink`](/0.9.0/utils/image/#imagesink). Here is an example showing how to save every tenth video frame as a separate image.
```python
>>> import supervision as sv
@@ -255,12 +506,12 @@ array([
... sink.save_image(image=image)
```
- Fixed [#106](https://github.com/roboflow/supervision/issues/106): inconvenient handling of [`sv.PolygonZone`](https://roboflow.github.io/supervision/detection/tools/polygon_zone/#polygonzone) coordinates. Now `sv.PolygonZone` accepts coordinates in the form of `[[x1, y1], [x2, y2], ...]` that can be both integers and floats.
- Fixed [#106](https://github.com/roboflow/supervision/issues/106): inconvenient handling of [`sv.PolygonZone`](/0.8.0/supervision/detection/tools/polygon_zone/#polygonzone) coordinates. Now `sv.PolygonZone` accepts coordinates in the form of `[[x1, y1], [x2, y2], ...]` that can be both integers and floats.
### 0.8.0 <small>May 17, 2023</small>
- Added [#100](https://github.com/roboflow/supervision/pull/100): support for dataset inheritance. The current `Dataset` got renamed to `DetectionDataset`. Now [`DetectionDataset`](https://roboflow.github.io/supervision/dataset/core/#detectiondataset) inherits from `BaseDataset`. This change was made to enforce the future consistency of APIs of different types of computer vision datasets.
- Added [#100](https://github.com/roboflow/supervision/pull/100): ability to save datasets in YOLO format using [`DetectionDataset.as_yolo`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.as_yolo).
- Added [#100](https://github.com/roboflow/supervision/pull/100): support for dataset inheritance. The current `Dataset` got renamed to `DetectionDataset`. Now [`DetectionDataset`](/0.8.0/supervision/dataset/core/#detectiondataset) inherits from `BaseDataset`. This change was made to enforce the future consistency of APIs of different types of computer vision datasets.
- Added [#100](https://github.com/roboflow/supervision/pull/100): ability to save datasets in YOLO format using [`DetectionDataset.as_yolo`](/0.8.0/dataset/core/#supervision.dataset.core.DetectionDataset.as_yolo).
```python
>>> import roboflow
@@ -284,7 +535,7 @@ array([
['dog', 'person']
```
- Added [#102](https://github.com/roboflow/supervision/pull/103): support for [`DetectionDataset.split`](https://roboflow.github.io/supervision/dataset/core/#supervision.dataset.core.DetectionDataset.split) allowing to divide `DetectionDataset` into two parts.
- Added [#102](https://github.com/roboflow/supervision/pull/103): support for [`DetectionDataset.split`](/0.8.0/dataset/core/#supervision.dataset.core.DetectionDataset.split) allowing to divide `DetectionDataset` into two parts.
```python
>>> import supervision as sv
+5 -1
View File
@@ -1,3 +1,7 @@
## Classifications
---
comments: true
---
# Classifications
:::supervision.classification.core.Classifications
+5
View File
@@ -0,0 +1,5 @@
# Code of conduct
```
--8<-- "CODE_OF_CONDUCT.md"
```
+1
View File
@@ -0,0 +1 @@
--8<-- "CONTRIBUTING.md"
+8
View File
@@ -0,0 +1,8 @@
---
template: cookbooks.html
comments: true
status: new
hide:
- navigation
- toc
---
+12 -2
View File
@@ -1,12 +1,22 @@
---
comments: true
---
# 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`.
## DetectionDataset
<div class="md-typeset">
<h2>DetectionDataset</h2>
</div>
:::supervision.dataset.core.DetectionDataset
## ClassificationDataset
<div class="md-typeset">
<h2>ClassificationDataset</h2>
</div>
:::supervision.dataset.core.ClassificationDataset
+18
View File
@@ -0,0 +1,18 @@
---
comments: true
status: deprecated
---
These features are phased out due to better alternatives or potential issues in future versions. Deprecated functionalities are supported for **three subsequent releases**, providing time for users to transition to updated methods.
- [`Detections.from_froboflow`](detection/core.md/#supervision.detection.core.Detections.from_roboflow) is deprecated and will be removed in `supervision-0.22.0`. Use [`Detections.from_inference`](detection/core.md/#supervision.detection.core.Detections.from_inference) instead.
- The method `Color.white()` is deprecated and will be removed in `supervision-0.22.0`. Use the constant `Color.WHITE` instead.
- The method `Color.black()` is deprecated and will be removed in `supervision-0.22.0`. Use the constant `Color.BLACK` instead.
- The method `Color.red()` is deprecated and will be removed in `supervision-0.22.0`. Use the constant `Color.RED` instead.
- The method `Color.green()` is deprecated and will be removed in `supervision-0.22.0`. Use the constant `Color.GREEN` instead.
- The method `Color.blue()` is deprecated and will be removed in `supervision-0.22.0`. Use the constant `Color.BLUE` instead.
- The method [`ColorPalette.default()`](draw/color.md/#supervision.draw.color.ColorPalette.default) is deprecated and will be removed in `supervision-0.22.0`. Use the constant [`ColorPalette.DEFAULT`](draw/color.md/#supervision.draw.color.ColorPalette.DEFAULT) instead.
- `BoxAnnotator` is deprecated and will be removed in `supervision-0.22.0`. Use [`BoundingBoxAnnotator`](annotators.md/#supervision.annotators.core.BoundingBoxAnnotator) and [`LabelAnnotator`](annotators.md/#supervision.annotators.core.LabelAnnotator) instead.
- The method [`FPSMonitor.__call__`](utils/video.md/#supervision.utils.video.FPSMonitor.__call__) is deprecated and will be removed in `supervision-0.22.0`. Use the attribute [`FPSMonitor.fps`](utils/video.md/#supervision.utils.video.FPSMonitor.fps) instead.
- The `track_buffer`, `track_thresh`, and `match_thresh` parameters in [`ByterTrack`](trackers.md/#supervision.tracker.byte_tracker.core.ByteTrack) are deprecated and will be removed in `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) is deprecated and will be removed in `supervision-0.23.0`. Use `triggering_anchors ` instead.
+6 -1
View File
@@ -1,3 +1,8 @@
## Detections
---
comments: true
status: new
---
# Detections
:::supervision.detection.core.Detections
+5 -1
View File
@@ -1,3 +1,7 @@
## InferenceSlicer
---
comments: true
---
# InferenceSlicer
:::supervision.detection.tools.inference_slicer.InferenceSlicer
+15
View File
@@ -0,0 +1,15 @@
---
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
+10 -2
View File
@@ -1,7 +1,15 @@
## PolygonZone
---
comments: true
---
<div class="md-typeset">
<h2>PolygonZone</h2>
</div>
:::supervision.detection.tools.polygon_zone.PolygonZone
## PolygonZoneAnnotator
<div class="md-typeset">
<h2>PolygonZoneAnnotator</h2>
</div>
:::supervision.detection.tools.polygon_zone.PolygonZoneAnnotator
+18
View File
@@ -0,0 +1,18 @@
---
comments: true
status: new
---
# 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
+53 -8
View File
@@ -1,27 +1,72 @@
## box_iou_batch
---
comments: true
status: new
---
# Detection Utils
<div class="md-typeset">
<h2>box_iou_batch</h2>
</div>
:::supervision.detection.utils.box_iou_batch
## non_max_suppression
<div class="md-typeset">
<h2>mask_iou_batch</h2>
</div>
:::supervision.detection.utils.non_max_suppression
:::supervision.detection.utils.mask_iou_batch
## polygon_to_mask
<div class="md-typeset">
<h2>box_non_max_suppression</h2>
</div>
:::supervision.detection.utils.box_non_max_suppression
<div class="md-typeset">
<h2>mask_non_max_suppression</h2>
</div>
:::supervision.detection.utils.mask_non_max_suppression
<div class="md-typeset">
<h2>polygon_to_mask</h2>
</div>
:::supervision.detection.utils.polygon_to_mask
## mask_to_xyxy
<div class="md-typeset">
<h2>mask_to_xyxy</h2>
</div>
:::supervision.detection.utils.mask_to_xyxy
## mask_to_polygons
<div class="md-typeset">
<h2>mask_to_polygons</h2>
</div>
:::supervision.detection.utils.mask_to_polygons
## polygon_to_xyxy
<div class="md-typeset">
<h2>polygon_to_xyxy</h2>
</div>
:::supervision.detection.utils.polygon_to_xyxy
## filter_polygons_by_area
<div class="md-typeset">
<h2>filter_polygons_by_area</h2>
</div>
:::supervision.detection.utils.filter_polygons_by_area
<div class="md-typeset">
<h2>move_boxes</h2>
</div>
:::supervision.detection.utils.move_boxes
<div class="md-typeset">
<h2>scale_boxes</h2>
</div>
:::supervision.detection.utils.scale_boxes
+13
View File
@@ -0,0 +1,13 @@
---
comments: true
---
# Color
:::supervision.draw.color.Color
<div class="md-typeset">
<h2>ColorPalette</h2>
</div>
:::supervision.draw.color.ColorPalette
+39 -5
View File
@@ -1,19 +1,53 @@
## draw_line
---
comments: true
---
# Draw Utils
<div class="md-typeset">
<h2>draw_line</h2>
</div>
:::supervision.draw.utils.draw_line
## draw_rectangle
<div class="md-typeset">
<h2>draw_rectangle</h2>
</div>
:::supervision.draw.utils.draw_rectangle
## draw_filled_rectangle
<div class="md-typeset">
<h2>draw_filled_rectangle</h2>
</div>
:::supervision.draw.utils.draw_filled_rectangle
## draw_polygon
<div class="md-typeset">
<h2>draw_polygon</h2>
</div>
:::supervision.draw.utils.draw_polygon
## draw_text
<div class="md-typeset">
<h2>draw_text</h2>
</div>
:::supervision.draw.utils.draw_text
<div class="md-typeset">
<h2>draw_image</h2>
</div>
:::supervision.draw.utils.draw_image
<div class="md-typeset">
<h2>calculate_optimal_font_scale</h2>
</div>
:::supervision.draw.utils.calculate_optimal_text_scale
<div class="md-typeset">
<h2>calculate_optimal_line_thickness</h2>
</div>
:::supervision.draw.utils.calculate_optimal_line_thickness
+5 -1
View File
@@ -1,3 +1,7 @@
## Position
---
comments: true
---
# Position
:::supervision.geometry.core.Position
+411 -1
View File
@@ -1 +1,411 @@
🚧 Page under construction.
---
comments: true
status: new
---
# Detect and Annotate
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 Inference
First, you'll need to obtain predictions from your object detection or segmentation
model.
=== "Inference"
```python
import cv2
from inference import get_model
model = get_model(model_id="yolov8n-640")
image = cv2.imread(<SOURCE_IMAGE_APTH>)
results = model.infer(image)[0]
```
=== "Ultralytics"
```python
import cv2
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
image = cv2.imread(<SOURCE_IMAGE_APTH>)
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(<SOURCE_IMAGE_APTH>)
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.
=== "Inference"
We can do so using the [`sv.Detections.from_inference`](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(<SOURCE_IMAGE_APTH>)
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
```
=== "Ultralytics"
We can do so using the [`sv.Detections.from_ultralytics`](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(<SOURCE_IMAGE_APTH>)
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
```
=== "Transformers"
We can do so using the [`sv.Detections.from_transformers`](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(<SOURCE_IMAGE_APTH>)
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`](/latest/detection/core/#supervision.detection.core.Detections.from_deepsparse) ([Deepsparse](https://github.com/neuralmagic/deepsparse))
- [`from_detectron2`](/latest/detection/core/#supervision.detection.core.Detections.from_detectron2) ([Detectron2](https://github.com/facebookresearch/detectron2))
- [`from_mmdetection`](/latest/detection/core/#supervision.detection.core.Detections.from_mmdetection) ([MMDetection](https://github.com/open-mmlab/mmdetection))
- [`from_sam`](/latest/detection/core/#supervision.detection.core.Detections.from_sam) ([Segment Anything Model](https://github.com/facebookresearch/segment-anything))
- [`from_yolo_nas`](/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.BoundingBoxAnnotator`](/latest/annotators/#supervision.annotators.core.BoundingBoxAnnotator) and [`sv.LabelAnnotator`](/latest/annotators/#supervision.annotators.core.LabelAnnotator) classes.
=== "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(<SOURCE_IMAGE_APTH>)
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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(<SOURCE_IMAGE_APTH>)
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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(<SOURCE_IMAGE_APTH>)
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)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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`](/latest/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(<PATH TO IMAGE>)
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence
in zip(detections['class_name'], detections.confidence)
]
annotated_image = bounding_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(<PATH TO IMAGE>)
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence
in zip(detections['class_name'], detections.confidence)
]
annotated_image = bounding_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(<PATH TO IMAGE>)
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)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
f"{class_name} {confidence:.2f}"
for class_name, confidence
in zip(detections['class_name'], detections.confidence)
]
annotated_image = bounding_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`](/latest/annotators/#supervision.annotators.core.MaskAnnotator)
is a drop-in replacement for
[`sv.BoundingBoxAnnotator`](/latest/annotators/#supervision.annotators.core.BoundingBoxAnnotator)
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(<PATH TO IMAGE>)
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)
```
=== "Ultralytics"
```python
import cv2
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n-seg.pt")
image = cv2.imread(<PATH TO IMAGE>)
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(<SOURCE_IMAGE_PATH>)
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)
+266
View File
@@ -0,0 +1,266 @@
---
comments: true
status: new
---
# 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`](/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.
=== "Inference"
```python
import cv2
import supervision as sv
from inference import get_model
model = get_model(model_id="yolov8x-640")
image = cv2.imread(<PATH TO IMAGE>)
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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(<PATH TO IMAGE>)
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = Image.open(<PATH TO IMAGE>)
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(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
model.config.id2label[class_id]
for class_id
in detections.class_id
]
annotated_image = bounding_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(<PATH TO IMAGE>)
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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(<PATH TO IMAGE>)
results = model(image, imgsz=1280)[0]
detections = sv.Detections.from_ultralytics(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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`](/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(<PATH TO IMAGE>)
def callback(image_slice: np.ndarray) -> sv.Detections:
results = model.infer(image_slice)[0]
detections = sv.Detections.from_inference(results)
slicer = sv.InferenceSlicer(callback = callback)
detections = slicer(image)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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(<PATH TO IMAGE>)
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)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated_image = bounding_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(<PATH TO IMAGE>)
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.size
target_size = torch.tensor([[height, width]])
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)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
model.config.id2label[class_id]
for class_id
in detections.class_id
]
annotated_image = bounding_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)
-1
View File
@@ -1 +0,0 @@
🚧 Page under construction.
+6 -1
View File
@@ -1,3 +1,9 @@
---
comments: true
---
# 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.
@@ -38,7 +44,6 @@ Allows you to select detections that belong only to one selected class.
</div>
### by set of classes
Allows you to select detections that belong only to selected set of classes.
-1
View File
@@ -1 +0,0 @@
🚧 Page under construction.
+319 -1
View File
@@ -1 +1,319 @@
🚧 Page under construction.
---
comments: true
---
# Track Objects
Leverage Supervision's advanced capabilities for enhancing your video analysis by
seamlessly [tracking](/latest/trackers/) objects recognized by
a multitude of object detection and segmentation 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.
To make it easier for you to follow our tutorial download the video we will use as an
example. You can do this using
[`supervision[assets]`](/latest/assets/) extension.
```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](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.
=== "Ultralytics"
```{ .py }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
box_annotator = sv.BoundingBoxAnnotator()
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.BoundingBoxAnnotator()
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 Supervision’s
[`sv.ByteTrack`](/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.
=== "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.BoundingBoxAnnotator()
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.BoundingBoxAnnotator()
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`](/latest/annotators.md/#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.BoundingBoxAnnotator()
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} {results.names[class_id]}"
for class_id, tracker_id
in zip(detections.class_id, 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.BoundingBoxAnnotator()
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} {results.names[class_id]}"
for class_id, tracker_id
in zip(detections.class_id, 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`](/latest/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.BoundingBoxAnnotator()
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} {results.names[class_id]}"
for class_id, tracker_id
in zip(detections.class_id, 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.BoundingBoxAnnotator()
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} {results.names[class_id]}"
for class_id, tracker_id
in zip(detections.class_id, 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>
This structured walkthrough should give a detailed pathway to annotate videos
effectively using Supervision’s various functionalities, including object tracking and
trace annotations.
+89 -13
View File
@@ -1,22 +1,37 @@
<div align="center">
<p>
<a align="center" href="" target="_blank">
<img
width="850"
src="https://media.roboflow.com/open-source/supervision/roboflow-supervision-banner.png?ik-sdk-version=javascript-1.4.3&updatedAt=1674062891088"
>
</a>
</p>
---
template: index.html
comments: true
hide:
- navigation
- toc
---
<div class="md-typeset">
<h1></h1>
</div>
<div align="center" id="logo">
<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>
## 👋 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` with pip in a
[**3.11>=Python>=3.8**](https://www.python.org/) environment.
You can install `supervision` in a
[**Python>=3.8**](https://www.python.org/) environment.
!!! example "pip install (recommended)"
@@ -31,7 +46,25 @@ You can install `supervision` with pip in a
If you require the full version of `supervision` with GUI support you can install the desktop version. This version includes the GUI components of OpenCV, allowing you to display images and videos on the screen.
```bash
pip install supervision[desktop]
pip install "supervision[desktop]"
```
!!! 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)"
@@ -46,6 +79,7 @@ You can install `supervision` with pip in a
# setup python environment and activate it
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
# headless install
pip install -e "."
@@ -62,7 +96,7 @@ You can install `supervision` with pip in a
cd supervision
# setup python environment and activate it
poetry env use python 3.10
poetry env use python3.10
poetry shell
# headless install
@@ -71,3 +105,45 @@ You can install `supervision` with pip in a
# desktop install
poetry install --extras "desktop"
```
## 🚀 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
- > __Filter Objects in Zone__
---
Master the techniques to selectively filter and focus on objects within a specific zone
</div>
+142
View File
@@ -0,0 +1,142 @@
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 url = element.getAttribute('data-url');
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}; z-index: ${zIndex};"
>
<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">
${authorAvatarsHTML}
<div class="author-names">${authorNamesHTML}</div>
</div>
`;
element.innerText = `
<a style="text-decoration: none; color: inherit;" href="${url}">
<div style="flex-direction: column; height: 100%; display: flex;
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: flex; flex: 0; justify-content: space-between">
<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">
${labelHTML}
</div>
</div>
</div>
</a>
`
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);
});
+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) });
+5
View File
@@ -0,0 +1,5 @@
# License
```
--8<-- "LICENSE.md"
```
+12 -2
View File
@@ -1,12 +1,22 @@
---
comments: true
---
#  Detection Metrics
!!! warning
Evaluation API is still fluid and may change. If you use Evaluation API in your project until further notice, freeze the
`supervision` version in your `requirements.txt` or `setup.py`.
## ConfusionMatrix
<div class="md-typeset">
<h2><a href="#supervision.metrics.detection.ConfusionMatrix">ConfusionMatrix</a></h2>
</div>
:::supervision.metrics.detection.ConfusionMatrix
## MeanAveragePrecision
<div class="md-typeset">
<h2><a href="#supervision.annotators.core.MeanAveragePrecision">MeanAveragePrecision</a></h2>
</div>
:::supervision.metrics.detection.MeanAveragePrecision
+400
View File
@@ -0,0 +1,400 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "TfUZYrKbqlF7"
},
"source": [
"# Annotate Video with Detections\n",
"\n",
"---\n",
"\n",
"[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/annotate-video-with-detections.ipynb)\n",
"\n",
"One of the most common requirements of computer vision applications is detecting objects in images and displaying bounding boxes around those objects. In this cookbook we'll walk through the steps on how to utilize the open source Roboflow ecosystem to accomplish this task on a video. Let's dive in!"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rUo1u17yqlF9"
},
"source": [
"## Before you start\n",
"\n",
"Let's make sure that we have access to GPU. We can use `nvidia-smi` command to do that. In case of any problems navigate to `Edit` -> `Notebook settings` -> `Hardware accelerator`, set it to `GPU`, and then click `Save`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "0Er370WTqlF9",
"outputId": "57b00a1e-87ea-4912-b4f9-5b94f0e6bf48",
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fri Feb 23 03:15:00 2024 \n",
"+---------------------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n",
"|-----------------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|=========================================+======================+======================|\n",
"| 0 Tesla V100-SXM2-16GB Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 33C P0 24W / 300W | 0MiB / 16384MiB | 0% Default |\n",
"| | | N/A |\n",
"+-----------------------------------------+----------------------+----------------------+\n",
" \n",
"+---------------------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=======================================================================================|\n",
"| No running processes found |\n",
"+---------------------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!nvidia-smi"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WuSnN7ejqlF-"
},
"source": [
"## Installing Dependencies\n",
"\n",
"In this cookbook we'll be utilizing the open source packages [Inference](https://inference.roboflow.com/) and [Supervision](https://supervision.roboflow.com/latest/) to accomplish our goals. Let's get those installed in our notebook with pip."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1YgQGum4qlF-",
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"!pip install -q inference-gpu \"supervision[assets]\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PZRnzh7EqlF-"
},
"source": [
"## Download a Video Asset\n",
"\n",
"First, let's download a video that we can detect objects in. Supervision comes with a great utility called Assets to help us hit the ground running. When we run this script, the video is saved in our local directory and can be accessed with the variable `path_to_video`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NMg4KOFiqlF-"
},
"outputs": [],
"source": [
"from supervision.assets import download_assets, VideoAssets\n",
"\n",
"# Download a supervision video asset\n",
"path_to_video = download_assets(VideoAssets.PEOPLE_WALKING)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "x93oxF0zrQOU"
},
"source": [
"As a result, we've downloaded a video. Let's take a look at the video below. Keep in mind that the video preview below works only in the web version of the cookbooks and not in Google Colab.\n",
"\n",
"<div style=\"display: flex; justify-content: center;\">\n",
" <video controls width=\"1000\"\">\n",
" <source\n",
" src=\"https://media.roboflow.com/supervision/video-examples/people-walking.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
" </video>\n",
"</div>\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "T8bU7fQ6qlF-"
},
"source": [
"## Detecting Objects\n",
"\n",
"For this example, the objects in the video that we'd like to detect are people. In order to display bounding boxes around the people in the video, we first need a way to detect them. We'll be using the open source [Inference](https://github.com/roboflow/inference) package for this task. Inference allows us to quickly use thousands of models, including fine tuned models from [Roboflow Universe](https://universe.roboflow.com/), with a few lines of code. We'll also utilize a few utilities for working with our video data from the [Supervision](https://github.com/roboflow/supervision) package."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hlONWHfQqlF-",
"outputId": "81b277fb-ea7c-4242-f49d-5af0c665ea58"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Detections(xyxy=array([[1140., 951., 1245., 1079.],\n",
" [ 666., 648., 745., 854.],\n",
" [ 34., 794., 142., 990.],\n",
" [1140., 505., 1211., 657.],\n",
" [ 260., 438., 332., 612.],\n",
" [1413., 702., 1523., 887.],\n",
" [1462., 472., 1543., 643.],\n",
" [1446., 318., 1516., 483.],\n",
" [ 753., 451., 821., 623.],\n",
" [ 924., 172., 983., 307.],\n",
" [1791., 144., 1852., 275.],\n",
" [ 93., 132., 146., 251.],\n",
" [ 708., 240., 765., 388.],\n",
" [ 200., 44., 267., 161.],\n",
" [1204., 131., 1255., 266.],\n",
" [ 569., 267., 628., 408.],\n",
" [1163., 150., 1210., 280.],\n",
" [ 799., 78., 847., 204.],\n",
" [1690., 152., 1751., 283.],\n",
" [ 344., 495., 396., 641.],\n",
" [1722., 77., 1782., 178.]]),\n",
" mask=None,\n",
" confidence=array([0.83215541, 0.80572134, 0.7919845 , 0.7912274 , 0.77121079,\n",
" 0.7599591 , 0.75711554, 0.75494027, 0.73076195, 0.71452248,\n",
" 0.69572842, 0.65269446, 0.63952065, 0.62914598, 0.61361706,\n",
" 0.5968492 , 0.55311316, 0.5470854 , 0.54070991, 0.52209878,\n",
" 0.41217673]),\n",
" class_id=array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),\n",
" tracker_id=None,\n",
" data={'class_name': array(['person', 'person', 'person', 'person', 'person', 'person',\n",
" 'person', 'person', 'person', 'person', 'person', 'person',\n",
" 'person', 'person', 'person', 'person', 'person', 'person',\n",
" 'person', 'person', 'person'], dtype='<U6')})\n"
]
}
],
"source": [
"import supervision as sv\n",
"from supervision.assets import download_assets, VideoAssets\n",
"from inference.models.utils import get_roboflow_model\n",
"\n",
"\n",
"# Load a yolov8 model from roboflow.\n",
"model = get_roboflow_model(\"yolov8s-640\")\n",
"\n",
"# Create a frame generator and video info object from supervision utilities.\n",
"frame_generator = sv.get_video_frames_generator(path_to_video)\n",
"\n",
"# Yield a single frame from the generator.\n",
"frame = next(frame_generator)\n",
"\n",
"# Run inference on our frame\n",
"result = model.infer(frame)[0]\n",
"\n",
"# Parse result into detections data model.\n",
"detections = sv.Detections.from_inference(result)\n",
"\n",
"# Pretty Print the resulting detections.\n",
"from pprint import pprint\n",
"pprint(detections)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "mL7QrQvyqlF-"
},
"source": [
"First, we load our model using the method `get_roboflow_model()`. Notice how we pass in a `model_id`? We're using an [alias](https://inference.roboflow.com/reference_pages/model_aliases/) here. This is where we can pass in other models from Roboflow Universe like this [rock, paper, scissors](https://universe.roboflow.com/roboflow-58fyf/rock-paper-scissors-sxsw) model utilizing our roboflow api key.\n",
"\n",
"```\n",
"model = get_roboflow_mode(\n",
" model_id=\"rock-paper-scissors-sxsw/11\",\n",
" api_key=\"roboflow_private_api_key\"\n",
")\n",
"```\n",
"\n",
"If you don't have an api key, you can [create an free Roboflow account](https://app.roboflow.com/login). This model wouldn't be much help with detecting people, but it's a nice exercise to see how our code becomes model agnostic!\n",
"\n",
"We then create a `frame_generator` object and yeild a single frame for inference using `next()`. We pass our frame to `model.infer()` to run inference. After, we pass that data into a little helpfer function called `sv.Detections.from_inference()` to parse it. Lastly we print our detections to show we are in fact detecting a few people in the frame!"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tM6geyUBwdej"
},
"source": [
"## Annotaing the Frame with Bounding Boxes\n",
"\n",
"Now that we're detecting images, let's get to the fun part. Let's annotate the frame and display the bounding boxes on the frame."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 560
},
"id": "8gkUxKei0RaV",
"outputId": "84a95332-70cf-4f26-c4bb-15479afafd04"
},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Create a bounding box annotator object.\n",
"bounding_box = sv.BoundingBoxAnnotator()\n",
"\n",
"# Annotate our frame with detections.\n",
"annotated_frame = bounding_box.annotate(scene=frame.copy(), detections=detections)\n",
"\n",
"# Display the frame.\n",
"sv.plot_image(annotated_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "o8SsyCid6YV3"
},
"source": [
"Notice that we create a `box_annoator` variable by initalizing a [BoundingBoxAnnotator](https://supervision.roboflow.com/latest/annotators/#boundingboxannotator). We can change the color and thickness, but for simplicity we keep the defaults. There are a ton of easy to use [annotators](https://supervision.roboflow.com/latest/annotators/) available in the Supervision package other than a bounding box that are fun to play with."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gKHSYO14vGC7"
},
"source": [
"## Saving Bounding Boxes to a Video\n",
"\n",
"Let's wrap up our code by utilizing a `VideoSink` to draw bounding boxes and save the resulting video. Take a peak at the final code example below. This can take a couple minutes deppending on your runtime and since since we're processing a full video. Feel free to skip ahead to see the resulting video."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Es4SUdPGqlF-"
},
"outputs": [],
"source": [
"from tqdm import tqdm\n",
"\n",
"# Create a video_info object for use in the VideoSink.\n",
"video_info = sv.VideoInfo.from_video_path(video_path=path_to_video)\n",
"\n",
"# Create a VideoSink context manager to save our frames.\n",
"with sv.VideoSink(target_path=\"output.mp4\", video_info=video_info) as sink:\n",
"\n",
" # Iterate through frames yielded from the frame_generator.\n",
" for frame in tqdm(frame_generator, total=video_info.total_frames):\n",
"\n",
" # Run inference on our frame.\n",
" result = model.infer(frame)[0]\n",
"\n",
" # Parse the result into the detections data model.\n",
" detections = sv.Detections.from_inference(result)\n",
"\n",
" # Apply bounding box to detections on a copy of the frame.\n",
" annotated_frame = bounding_box.annotate(\n",
" scene=frame.copy(),\n",
" detections=detections\n",
" )\n",
"\n",
" # Write the annotated frame to the video sink.\n",
" sink.write_frame(frame=annotated_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "EXTE3zWxqlF-"
},
"source": [
"<div style=\"display: flex; justify-content: center;\">\n",
" <video controls width=\"1000\">\n",
" <source\n",
" src=\"https://storage.googleapis.com/com-roboflow-marketing/supervision/cookbooks/annotate-video-with-detections.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
" </video>\n",
"</div>\n",
"<br>\n",
"\n",
"\n",
"In the code above we've created a`video_info` variable to pass information about the video to our `VideoSink`. The `VideoSink` is a cool little context manager that allows us to `write_frames()` to a video ouput file. We're also optionally using `tqdm` to display a progress bar with a % complete. We only scratched the surface of all of the customizable Annotators and additional features that Supervision and Inference have to offer. Stay tuned for more cookbooks on how to take advantge of them in your computer vision applications. Happy building! \ud83d\ude80"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "V100",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
+708
View File
@@ -0,0 +1,708 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "L1RnMc9XCWop"
},
"source": [
"# Count Objects Crossing the Line\n",
"\n",
"---\n",
"\n",
"[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/count-objects-crossing-the-line.ipynb)\n",
"[![YouTube](https://badges.aleen42.com/src/youtube.svg)](https://youtu.be/OS5qI9YBkfk)\n",
"[![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/yolov8-tracking-and-counting/)"
]
},
{
"cell_type": "markdown",
"source": [
"Click the `Open in Colab` button to run the cookbook on Google Colab."
],
"metadata": {
"id": "IyC-iI62u9y7"
}
},
{
"cell_type": "markdown",
"metadata": {
"id": "0fRV0VyTFa4v"
},
"source": [
"## Before you start\n",
"\n",
"Let's make sure that we have access to GPU. We can use `nvidia-smi` command to do that. In case of any problems navigate to `Edit` -> `Notebook settings` -> `Hardware accelerator`, set it to `GPU`, and then click `Save`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nD3EEfKzFftV",
"outputId": "af204c68-c7ef-4365-e2b0-b40583d7f502"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Mon Feb 12 13:03:38 2024 \n",
"+---------------------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n",
"|-----------------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|=========================================+======================+======================|\n",
"| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 48C P8 10W / 70W | 0MiB / 15360MiB | 0% Default |\n",
"| | | N/A |\n",
"+-----------------------------------------+----------------------+----------------------+\n",
" \n",
"+---------------------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=======================================================================================|\n",
"| No running processes found |\n",
"+---------------------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!nvidia-smi"
]
},
{
"cell_type": "markdown",
"source": [
"**NOTE:** To make it easier for us to manage datasets, images and models we create a `HOME` constant."
],
"metadata": {
"id": "S_coxWaEwNpB"
}
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "AO4MWPmnFk7m",
"outputId": "690d019e-8833-44a1-ed9a-ae2ce248ef20"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"/content\n"
]
}
],
"source": [
"import os\n",
"HOME = os.getcwd()\n",
"print(HOME)"
]
},
{
"cell_type": "markdown",
"source": [
"## Install required packages\n",
"\n",
"In this cookbook, we'll leverage two Python packages - `ultralytics` for running object detection, and `supervision` for tracking, visualizing detections, and crucially, counting objects that cross a line."
],
"metadata": {
"id": "PE1dQcgiLuvV"
}
},
{
"cell_type": "code",
"source": [
"!pip install -q ultralytics supervision==0.18.0"
],
"metadata": {
"id": "Yy86T0CJLz1Y"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Imports"
],
"metadata": {
"id": "FC-EZ6-fMEfA"
}
},
{
"cell_type": "code",
"source": [
"import numpy as np\n",
"import supervision as sv\n",
"\n",
"from ultralytics import YOLO\n",
"from supervision.assets import download_assets, VideoAssets"
],
"metadata": {
"id": "Q8rPpDW4MEGU"
},
"execution_count": 4,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "hZkBCNk9F6NO"
},
"source": [
"## Download video"
]
},
{
"cell_type": "markdown",
"source": [
"\n",
"As an example input video, we will use one of the videos available in [`supervision.assets`](https://supervision.roboflow.com/develop/assets/). Supervision offers an assets download utility that allows you to download video files that you can use in your demos."
],
"metadata": {
"id": "Ax3dupz7z0vn"
}
},
{
"cell_type": "code",
"source": [
"download_assets(VideoAssets.VEHICLES)"
],
"metadata": {
"id": "tmfK_kmjMtHp"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"**NOTE:** If you want to run the cookbook using your own file as input, simply upload video to Google Colab and replace `SOURCE_VIDEO_PATH` with the path to your file."
],
"metadata": {
"id": "-G9vhVBl2i-P"
}
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"id": "Y3DjvPRiGIht"
},
"outputs": [],
"source": [
"SOURCE_VIDEO_PATH = f\"{HOME}/vehicles.mp4\""
]
},
{
"cell_type": "markdown",
"source": [
"As a result of executing the above commands, you will download a video file and save it at the `SOURCE_VIDEO_PATH`. Keep in mind that the video preview below works only in the web version of the cookbooks and not in Google Colab.\n",
"\n",
"<video controls>\n",
" <source\n",
" src=\"https://storage.googleapis.com/com-roboflow-marketing/supervision/cookbooks/vehicles-1280x720.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
"</video>"
],
"metadata": {
"id": "cZaQUyUrZAek"
}
},
{
"cell_type": "markdown",
"source": [
"## Read single frame from video"
],
"metadata": {
"id": "iiS871HqNnll"
}
},
{
"cell_type": "markdown",
"source": [
"The [`get_video_frames_generator`](https://supervision.roboflow.com/latest/utils/video/#supervision.utils.video.get_video_frames_generator) enables us to easily iterate over video frames. Let's create a video generator for our sample input file and display its first frame on the screen."
],
"metadata": {
"id": "MPMlQs-22HX9"
}
},
{
"cell_type": "code",
"source": [
"generator = sv.get_video_frames_generator(SOURCE_VIDEO_PATH)\n",
"frame = next(generator)\n",
"\n",
"sv.plot_image(frame, (12, 12))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 560
},
"id": "6jm4yX-3Ou_B",
"outputId": "b5799261-2ac9-40a3-ae4a-cb0548a2c034"
},
"execution_count": 7,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"\n",
"We can also use [`VideoInfo.from_video_path`](https://supervision.roboflow.com/develop/utils/video/#supervision.utils.video.VideoInfo) to learn basic information about our video, such as duration, resolution, or FPS."
],
"metadata": {
"id": "L4pt1XDO3D7q"
}
},
{
"cell_type": "code",
"source": [
"sv.VideoInfo.from_video_path(SOURCE_VIDEO_PATH)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "eVLsW_I72eXa",
"outputId": "9182624b-2de5-47d1-a5ed-73dc60ed5e8a"
},
"execution_count": 8,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"VideoInfo(width=3840, height=2160, fps=25, total_frames=538)"
]
},
"metadata": {},
"execution_count": 8
}
]
},
{
"cell_type": "markdown",
"source": [
"## Run Object Detection\n",
"\n",
"Let's start by running the detection model on the first frame and annotating the results. In this cookbook, we use [Ultralytics](https://github.com/ultralytics/ultralytics) YOLOv8, but it can be successfully replaced with [other models](https://supervision.roboflow.com/latest/detection/core)."
],
"metadata": {
"id": "N0-qK6vDPsr-"
}
},
{
"cell_type": "markdown",
"source": [
"We initiate the model and perform detection on the first frame of the video. Then, we convert the result into a [`sv.Detections`](https://supervision.roboflow.com/latest/detection/core/) object, which will be useful in the later parts of the cookbook."
],
"metadata": {
"id": "uGJKBHXnc1w3"
}
},
{
"cell_type": "code",
"source": [
"model = YOLO(\"yolov8x.pt\")\n",
"\n",
"results = model(frame, verbose=False)[0]\n",
"detections = sv.Detections.from_ultralytics(results)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NW0G6ZKX1e1E",
"outputId": "91687b08-667e-46c2-a421-e26fefc3388b"
},
"execution_count": 9,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Downloading https://github.com/ultralytics/assets/releases/download/v8.1.0/yolov8x.pt to 'yolov8x.pt'...\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 131M/131M [00:00<00:00, 241MB/s]\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"\n",
"The results we've obtained can be easily visualized with [`sv.BoundingBoxAnnotator`](https://supervision.roboflow.com/latest/annotators/#supervision.annotators.core.BoundingBoxAnnotator). By default, this annotator uses the same color to highlight objects of the same category. However, with the integration of a [tracker](https://supervision.roboflow.com/latest/trackers/), it becomes possible to assign unique colors to each tracked object. We can easily define our [own color palettes](https://supervision.roboflow.com/latest/draw/color/#supervision.draw.color.ColorPalette) and adjust parameters such as line thickness, allowing for a highly tailored visualization experience."
],
"metadata": {
"id": "zL56OvvfdYpB"
}
},
{
"cell_type": "code",
"source": [
"bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=4)\n",
"annotated_frame = bounding_box_annotator.annotate(frame.copy(), detections)\n",
"sv.plot_image(annotated_frame, (12, 12))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 560
},
"id": "qpjNci4iRGkJ",
"outputId": "b0ddb63b-9640-40b9-d8f4-e555195f0134"
},
"execution_count": 10,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Improve Vizualizations"
],
"metadata": {
"id": "HsPNfuM_3ENR"
}
},
{
"cell_type": "markdown",
"source": [
"Supervision annotators can be easily combined with one another. Let's enhance our visualization by adding [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/annotators/#supervision.annotators.core.PolygonAnnotator.annotate), which we will use to mark detections with a label indicating their category and confidence level."
],
"metadata": {
"id": "H4lp2Ao_fHit"
}
},
{
"cell_type": "code",
"source": [
"labels = [\n",
" f\"{results.names[class_id]} {confidence:0.2f}\"\n",
" for class_id, confidence\n",
" in zip(detections.class_id, detections.confidence)\n",
"]\n",
"\n",
"bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=4)\n",
"label_annotator = sv.LabelAnnotator(text_thickness=4, text_scale=2)\n",
"\n",
"annotated_frame = frame.copy()\n",
"annotated_frame = bounding_box_annotator.annotate(annotated_frame, detections)\n",
"annotated_frame = label_annotator.annotate(annotated_frame, detections, labels)\n",
"sv.plot_image(annotated_frame, (12, 12))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 560
},
"id": "lIYQULBI3Tf3",
"outputId": "8cd8d367-9003-4ac8-d62e-d81d38d2faeb"
},
"execution_count": 12,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Define Line Position"
],
"metadata": {
"id": "WZHe1xq_633e"
}
},
{
"cell_type": "markdown",
"source": [
"To set the position of `sv.LineZone`, we need to define the `start` and `end` points. The position of each point is defined as a pair of coordinates `(x, y)`. The origin of the coordinate system is located in the top-left corner of the frame. The `x` axis runs from left to right, and the `y` axis runs from top to bottom.\n",
"\n",
"I decided to place my line horizontally, at the midpoint of the frame's height. I obtained the full dimensions of the frame using [`sv.VideoInfo`](https://supervision.roboflow.com/develop/utils/video/#supervision.utils.video.VideoInfo).\n"
],
"metadata": {
"id": "iniUELOr5hZ_"
}
},
{
"cell_type": "code",
"source": [
"sv.VideoInfo.from_video_path(SOURCE_VIDEO_PATH)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pqwq-1OYihyB",
"outputId": "3c74086d-7c1c-42f9-b8dc-25dc74b2e35a"
},
"execution_count": 14,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"VideoInfo(width=3840, height=2160, fps=25, total_frames=538)"
]
},
"metadata": {},
"execution_count": 14
}
]
},
{
"cell_type": "markdown",
"source": [
"The line we've created, together with the `in_count` and `out_count`, can be elegantly visualized using [`sv.LineZoneAnnotator`](https://supervision.roboflow.com/latest/detection/tools/line_zone/#supervision.detection.line_zone.LineZoneAnnotator). This tool also allows for extensive customization options; we can alter the color of both the line and the text, opt to hide the in/out counts, and adjust the labels. By default, the labels are set to `in` and `out`, but they can be tailored to fit the context of our project, providing a clear and intuitive display of object movement across the designated line."
],
"metadata": {
"id": "WBavHZsdijjR"
}
},
{
"cell_type": "code",
"source": [
"START = sv.Point(0, 1500)\n",
"END = sv.Point(3840, 1500)\n",
"\n",
"line_zone = sv.LineZone(start=START, end=END)\n",
"\n",
"line_zone_annotator = sv.LineZoneAnnotator(\n",
" thickness=4,\n",
" text_thickness=4,\n",
" text_scale=2)\n",
"\n",
"annotated_frame = frame.copy()\n",
"annotated_frame = line_zone_annotator.annotate(annotated_frame, line_counter=line_zone)\n",
"sv.plot_image(annotated_frame, (12, 12))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 560
},
"id": "gqdGQABx7BzA",
"outputId": "42bb2e1c-ab6c-4e3d-b286-d78f0a959d7c"
},
"execution_count": 22,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Process Video"
],
"metadata": {
"id": "2Mq56vXt8H9b"
}
},
{
"cell_type": "code",
"source": [
"byte_tracker = sv.ByteTrack()"
],
"metadata": {
"id": "ayaocyX28ykm"
},
"execution_count": 18,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"For an even better visualization, we will add another annotator - `sv.TraceAnnotator`, which allows for drawing the path traversed by each object over the last few frames. We will use it in combination with `sv.BoundingBoxAnnotator` and `sv.LabelAnnotator`, which we became familiar with earlier."
],
"metadata": {
"id": "UJwZ8KVSln-_"
}
},
{
"cell_type": "code",
"source": [
"bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=4)\n",
"label_annotator = sv.LabelAnnotator(text_thickness=4, text_scale=2)\n",
"trace_annotator = sv.TraceAnnotator(thickness=4)"
],
"metadata": {
"id": "WpKDAJny9n3D"
},
"execution_count": 17,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"All the operations we plan to perform for each frame of our video - detection, tracking, annotation, and counting - are encapsulated in a function named `callback`."
],
"metadata": {
"id": "8_slr3hrlX20"
}
},
{
"cell_type": "code",
"source": [
"def callback(frame: np.ndarray, index:int) -> np.ndarray:\n",
" results = model(frame, verbose=False)[0]\n",
" detections = sv.Detections.from_ultralytics(results)\n",
" detections = byte_tracker.update_with_detections(detections)\n",
"\n",
" labels = [\n",
" f\"#{tracker_id} {model.model.names[class_id]} {confidence:0.2f}\"\n",
" for confidence, class_id, tracker_id\n",
" in zip(detections.confidence, detections.class_id, detections.tracker_id)\n",
" ]\n",
"\n",
" annotated_frame = frame.copy()\n",
" annotated_frame = trace_annotator.annotate(\n",
" scene=annotated_frame,\n",
" detections=detections)\n",
" annotated_frame = bounding_box_annotator.annotate(\n",
" scene=annotated_frame,\n",
" detections=detections)\n",
" annotated_frame = label_annotator.annotate(\n",
" scene=annotated_frame,\n",
" detections=detections,\n",
" labels=labels)\n",
"\n",
" line_zone.trigger(detections)\n",
"\n",
" return line_zone_annotator.annotate(annotated_frame, line_counter=line_zone)"
],
"metadata": {
"id": "-Qs07-Ml-ETD"
},
"execution_count": 19,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Finally, we are ready to process our entire video. We will use [`sv.process_video`](https://supervision.roboflow.com/develop/utils/video/#supervision.utils.video.process_video) and pass to it the previously defined `SOURCE_VIDEO_PATH`, `TARGET_VIDEO_PATH`, and `callback`."
],
"metadata": {
"id": "h8ip4Nmm5Gcm"
}
},
{
"cell_type": "code",
"source": [
"TARGET_VIDEO_PATH = f\"{HOME}/count-objects-crossing-the-line-result.mp4\""
],
"metadata": {
"id": "2RHSS5hAmlnd"
},
"execution_count": 21,
"outputs": []
},
{
"cell_type": "code",
"source": [
"sv.process_video(\n",
" source_path = SOURCE_VIDEO_PATH,\n",
" target_path = TARGET_VIDEO_PATH,\n",
" callback=callback\n",
")"
],
"metadata": {
"id": "a7F5Ij-Q-TWx"
},
"execution_count": 20,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
" Keep in mind that the video preview below works only in the web version of the cookbooks and not in Google Colab.\n",
"\n",
"<video controls>\n",
" <source\n",
" src=\"https://storage.googleapis.com/com-roboflow-marketing/supervision/cookbooks/count-objects-crossing-the-line-result-1280x720.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
"</video>"
],
"metadata": {
"id": "Oxc4X5S7ffEw"
}
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
+102
View File
@@ -0,0 +1,102 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Download Supervision Assets\n",
"\n",
"---\n",
"\n",
"[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/download-supervision-assets.ipynb)\n",
"\n",
"When experimenting with interesting and useful features of the Supervision package, it's important to have some sort of image or video data to experiment with. Luckily for us, Supervision ships with [Assets](https://supervision.roboflow.com/latest/assets/)! Assets is a collection of videos that you can utilize to start experimenting with the various features Supervision has to offer. Let's take a look at how to use this resource.\n",
"\n",
"## Install Dependencies"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"!pip install -q \"supervision[assets]\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Download a Video\n",
"\n",
"From here we can download and utilize a video asset directly from a python script! Note below that we're utilizing the method `download_assets` to download the `VideoAssets.SUBWAY` video to our local directory. This method returns the file path, so we can then utilize this path for additional experimentation. From here, you will see a video asset to experiment with in your local directory. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from supervision.assets import download_assets, VideoAssets\n",
"\n",
"# Download the a video of the subway.\n",
"path_to_video = download_assets(VideoAssets.SUBWAY)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With this, we now have a high quality video asset for use in demos. Let's take a look at what we downloaded. Keep in mind that the video preview below works only in the web version of the cookbooks and not in Google Colab.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div style=\"display: flex; justify-content: center;\">\n",
" <video controls width=\"320\" height=\"240\">\n",
" <source\n",
" src=\"https://media.roboflow.com/supervision/video-examples/subway.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
" </video>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're now equipt with a video asset from Supervision to run some experiments on! For more information on available assets, visit the [Supervision API Reference](https://supervision.roboflow.com/latest/assets). Happy building!"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@@ -0,0 +1,566 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"gpuType": "T4"
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"source": [
"# Evaluating Alignment of Text-to-image Diffusion Models\n",
"\n",
"---\n",
"\n",
"[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/evaluating-alignment-of-text-to-image-diffusion-models.ipynb)\n",
"\n",
"Click the `Open in Colab` button to run the cookbook on Google Colab."
],
"metadata": {
"id": "pviK1VFFNp8h"
}
},
{
"cell_type": "markdown",
"source": [
"## Introduction\n",
"\n",
"It is a common scenario to evaluate text-to-image models for its alignment to the prompt. One way to test it is to use a set of prompts, consisting of number of objects and their basic physical properties (e.g. color), to generate images and manually evaluate the results. This process can be greatly improved using object detection models."
],
"metadata": {
"id": "FtZXoFjPt569"
}
},
{
"cell_type": "markdown",
"source": [
"## Before you start\n",
"\n",
"Let's make sure that we have access to GPU. We can use `nvidia-smi` command to do that. In case of any problems navigate to `Edit` -> `Notebook settings` -> `Hardware accelerator`, set it to `GPU`, and then click `Save`."
],
"metadata": {
"id": "1yOkAwH-UYPM"
}
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MVfLwWd8D1ne",
"outputId": "70562805-224c-41ad-cf46-f6808f469923"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Thu Feb 29 18:16:26 2024 \n",
"+---------------------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n",
"|-----------------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|=========================================+======================+======================|\n",
"| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 46C P8 9W / 70W | 0MiB / 15360MiB | 0% Default |\n",
"| | | N/A |\n",
"+-----------------------------------------+----------------------+----------------------+\n",
" \n",
"+---------------------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=======================================================================================|\n",
"| No running processes found |\n",
"+---------------------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!nvidia-smi"
]
},
{
"cell_type": "markdown",
"source": [
"## Install required packages\n",
"\n",
"In this cookbook, we'll leverage the following Python packages:\n",
"* [diffusers](https://huggingface.co/docs/diffusers/en/index) for image generation pipelines,\n",
"* [inference](https://inference.roboflow.com/) for running object detection,\n",
"* [supervision](https://supervision.roboflow.com/) for visualizing detections."
],
"metadata": {
"id": "xg5JFGa4UjZq"
}
},
{
"cell_type": "code",
"source": [
"!pip install -q torch diffusers accelerate inference-gpu[yolo-world] dill git+https://github.com/openai/CLIP.git supervision==0.19.0rc5"
],
"metadata": {
"id": "ri8GPZ3SD7LT"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Imports"
],
"metadata": {
"id": "U0qBpU5YU3P9"
}
},
{
"cell_type": "code",
"source": [
"import itertools\n",
"import cv2\n",
"from diffusers import StableDiffusionXLPipeline\n",
"import numpy as np\n",
"from PIL import Image\n",
"import supervision as sv\n",
"import torch\n",
"from inference.models import YOLOWorld"
],
"metadata": {
"id": "sBKUQMdwJTv1"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Generating an image\n",
"\n",
"We'll use [SDXL](https://huggingface.co/docs/diffusers/using-diffusers/sdxl) model to generate our image. Let's initialize our pipeline first:"
],
"metadata": {
"id": "ZzEhndAyU_EF"
}
},
{
"cell_type": "code",
"source": [
"pipeline = StableDiffusionXLPipeline.from_pretrained(\n",
" \"stabilityai/stable-diffusion-xl-base-1.0\",\n",
" torch_dtype=torch.float16,\n",
" variant=\"fp16\",\n",
" use_safetensors=True,\n",
").to(\"cuda\")"
],
"metadata": {
"id": "qCwxwGcuEHJ-"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"In this example, we'll focus on generating an image of a black cat playing with a blue ball next to a parked white car. We don't care about the aesthetic aspect of the image."
],
"metadata": {
"id": "XrQ8ose0Vm-T"
}
},
{
"cell_type": "code",
"source": [
"PROMPT = \"a black cat playing with a blue ball next to a parked white car, wide angle, photorealistic\"\n",
"NEGATIVE_PROMPT = \"low quality, blurred, text, illustration\"\n",
"WIDTH, HEIGHT = 1024, 768\n",
"SEED = 9213799\n",
"\n",
"image = pipeline(\n",
" prompt=PROMPT,\n",
" negative_prompt=NEGATIVE_PROMPT,\n",
" generator=torch.manual_seed(SEED),\n",
" width=WIDTH,\n",
" height=HEIGHT,\n",
").images[0]\n",
"image"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 817,
"referenced_widgets": [
"80345cfe8a724651a287a20078218742",
"b79d4e509fa54f899391ff0ca80730c3",
"16cbb7e6ec6d444e8d71042afaf98806",
"4e3ebed950c945a0a7d74acaf8a4e071",
"0c2fc95f4da4409d8789c1086efc7487",
"a677a168d3dc46f48a6bd9877bf2873a",
"df3cb55850ba40afb692bca7f7557bbf",
"abb0cd4b86ed4d1bbb5bede80355be74",
"b403cba7f1ff4cd0a4a850de46bc7d3e",
"40ee234278f0466587191689f3a4e77d",
"48df83b840204738a2530fc222a17dc9"
]
},
"id": "TaWaIpjQERtf",
"outputId": "236e6107-b50f-4eb8-8db8-234519245264"
},
"execution_count": 41,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
" 0%| | 0/50 [00:00<?, ?it/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "80345cfe8a724651a287a20078218742"
}
},
"metadata": {}
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"<PIL.Image.Image image mode=RGB size=1024x768>"
],
"image/png": "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 truncated
},
"metadata": {},
"execution_count": 41
}
]
},
{
"cell_type": "markdown",
"source": [
"Not bad! The results seem to be well-aligned with the prompt.\n",
"\n",
"## Detecting objects\n",
"\n",
"Now, let's see how can we detect the objects automatically. For this, we'll use [YOLO-World](https://inference.roboflow.com/) model from `inference` library."
],
"metadata": {
"id": "wKuyU-GDXPhr"
}
},
{
"cell_type": "code",
"source": [
"model = YOLOWorld(model_id=\"yolo_world/l\")"
],
"metadata": {
"id": "R9pERjDkGIlN"
},
"execution_count": 42,
"outputs": []
},
{
"cell_type": "markdown",
"source": [],
"metadata": {
"id": "G0PlnmZckOCH"
}
},
{
"cell_type": "markdown",
"source": [
"YOLO-World model allows us to [define our own set of labels](https://docs.ultralytics.com/models/yolo-world/#set-prompts). Let's create it by combining lists of pre-defined colors and objects."
],
"metadata": {
"id": "VOxtES_qaoWe"
}
},
{
"cell_type": "code",
"source": [
"COLORS = [\"green\", \"yellow\", \"black\", \"blue\", \"red\", \"white\", \"orange\"]\n",
"OBJECTS = [\"car\", \"cat\", \"ball\", \"dog\", \"tree\", \"house\", \"person\"]\n",
"CLASSES = [f\"{color} {obj}\" for color, obj in itertools.product(COLORS, OBJECTS)]\n",
"print(\"Number of labels:\", len(CLASSES))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SkY3TI4JHmkj",
"outputId": "253a95a8-0c32-403a-db63-82e529de2eba"
},
"execution_count": 43,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Number of labels: 49\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"Let's feed these labels into our model:"
],
"metadata": {
"id": "by_NYnqkoET-"
}
},
{
"cell_type": "code",
"source": [
"model.set_classes(CLASSES)"
],
"metadata": {
"id": "oinXZU3YWZqw"
},
"execution_count": 44,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Time to detect some objects!"
],
"metadata": {
"id": "RTHHpRsFoJsk"
}
},
{
"cell_type": "code",
"source": [
"results = model.infer(image)"
],
"metadata": {
"id": "zDPd-LOqGLHJ"
},
"execution_count": 45,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"We'll convert the results to the [sv.Detections](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections) format to enable features like filtering or annotations."
],
"metadata": {
"id": "TGCRxUpeu8Vi"
}
},
{
"cell_type": "code",
"source": [
"detections = sv.Detections.from_inference(results)"
],
"metadata": {
"id": "GWbmFKscvUhU"
},
"execution_count": 46,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Speaking of which: we only care about strong detections, so we filter out ones that are below 0.6 confidence."
],
"metadata": {
"id": "AscEY8SioQQ7"
}
},
{
"cell_type": "code",
"source": [
"valid_detections = detections[detections.confidence >= 0.6]"
],
"metadata": {
"id": "f2fvqc8lWxGT"
},
"execution_count": 47,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"A quick peek on the detected labels and their score:"
],
"metadata": {
"id": "klstslXPop-9"
}
},
{
"cell_type": "code",
"source": [
"labels = [\n",
" f\"{CLASSES[class_id]} {confidence:0.2f}\"\n",
" for class_id, confidence\n",
" in zip(valid_detections.class_id, valid_detections.confidence)\n",
"]\n",
"labels"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "0jbyOEGdGOhd",
"outputId": "a7a90eb0-d829-40d3-8090-151e2c735d8c"
},
"execution_count": 48,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['blue ball 0.95', 'black cat 0.72', 'white car 0.68']"
]
},
"metadata": {},
"execution_count": 48
}
]
},
{
"cell_type": "markdown",
"source": [
"## Visualizing results\n",
"\n",
"Now, let's use the power of `supervision` to visualize them. Our output image is in [Pillow](https://pillow.readthedocs.io/en/stable/index.html) format, but annotators can accept the image to be a BGR `np.ndarray` or pillow's `PIL.Image.Image`.\n",
"\n",
"Time to define how we want our detections to be visualized. A combination of [sv.BoundingBoxAnnotator](https://supervision.roboflow.com/latest/annotators/#supervision.annotators.core.BoundingBoxAnnotator) and [sv.LabelAnnotator](https://supervision.roboflow.com/latest/annotators/#supervision.annotators.core.LabelAnnotator) should be perfect."
],
"metadata": {
"id": "GOccbqMDo2Ec"
}
},
{
"cell_type": "code",
"source": [
"bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=2)\n",
"label_annotator = sv.LabelAnnotator(text_thickness=1, text_scale=0.5,text_color=sv.Color.BLACK)"
],
"metadata": {
"id": "X9HMMnTppp-c"
},
"execution_count": 49,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Finally, annotating our image is as simple as calling `annotate` methods from our annotators:"
],
"metadata": {
"id": "u3y59TgWp4Fx"
}
},
{
"cell_type": "code",
"source": [
"annotated_image = bounding_box_annotator.annotate(image, valid_detections)\n",
"annotated_image = label_annotator.annotate(annotated_image, valid_detections, labels)\n",
"\n",
"sv.plot_image(annotated_image, (12, 12))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 734
},
"id": "UdDEwjhoIiHo",
"outputId": "c56bd631-653c-4fd6-cc41-653abc49b0e7"
},
"execution_count": 50,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Testing it automatically\n",
"\n",
"We can also test if all requested objects are in the generated image by comparing a set of ground-truth labels with predicted ones:"
],
"metadata": {
"id": "kl5kO59CquMq"
}
},
{
"cell_type": "code",
"source": [
"GROUND_TRUTH = {\"black cat\", \"blue ball\", \"white car\"}\n",
"prediction = {CLASSES[class_id] for class_id in valid_detections.class_id}\n",
"\n",
"prediction.issubset(GROUND_TRUTH)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "laJS1E76qynK",
"outputId": "de193606-b41a-445d-8107-de02218190bd"
},
"execution_count": 51,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"True"
]
},
"metadata": {},
"execution_count": 51
}
]
},
{
"cell_type": "markdown",
"source": [
"Using [sv.Detections](https://supervision.roboflow.com/latest/detection/core/#supervision.detection.core.Detections) makes it super easy to do."
],
"metadata": {
"id": "8L4lXpvFvxZR"
}
},
{
"cell_type": "markdown",
"source": [
"## Next steps\n",
"\n",
"In this tutorial you learned how to detect and visualize objects for a simple image generation evaluation study.\n",
"\n",
"Having a pipeline capable of evaluating a single image, the natural next step should be to run it on a set of pre-defined scenarios and calculate metrics."
],
"metadata": {
"id": "j2GgYtNGqYmY"
}
}
]
}
+319
View File
@@ -0,0 +1,319 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "BsraWznGULVc"
},
"source": [
"# Object Tracking\n",
"\n",
"---\n",
"\n",
"[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/object-tracking.ipynb)\n",
"\n",
"In some cases, it's important for us to track objects across multiple frames of a video. For example, we may need to figure out the direction a vehicle is moving, or count objects in a frame. Some Supervision [Annotators](https://supervision.roboflow.com/latest/annotators/) and Tools like [LineZone](https://supervision.roboflow.com/latest/detection/tools/line_zone/) require tracking to be setup. In this cookbook, we'll cover how to get a tracker up and running for use in your computer vision applications.\n",
"\n",
"## What is a Tracker?\n",
"\n",
"Trackers are a piece of code that identifies objects across frames and assigns them a unique `tracker_id`. There are a few popular trackers at the time of writing this including ByteTrack and Bot-SORT. Supervision makes using trackers a breeze and comes with ByteTrack built-in."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7h__vutkUZSY"
},
"source": [
"## Before you start\n",
"\n",
"Let's make sure that we have access to GPU. We can use `nvidia-smi` command to do that. In case of any problems navigate to `Edit` -> `Notebook settings` -> `Hardware accelerator`, set it to `GPU`, and then click `Save`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pzm2gQlYUbmd",
"outputId": "71217cbf-f7d0-4496-c150-1c363386a16f",
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Fri Feb 23 03:18:02 2024 \n",
"+---------------------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n",
"|-----------------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|=========================================+======================+======================|\n",
"| 0 Tesla V100-SXM2-16GB Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 33C P0 24W / 300W | 0MiB / 16384MiB | 0% Default |\n",
"| | | N/A |\n",
"+-----------------------------------------+----------------------+----------------------+\n",
" \n",
"+---------------------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=======================================================================================|\n",
"| No running processes found |\n",
"+---------------------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!nvidia-smi"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZI4EwAnEUTFC"
},
"source": [
"## Install Dependencies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NaEjHlAWULVd"
},
"outputs": [],
"source": [
"!pip install -q inference-gpu \"supervision[assets]\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "zUKICBWFULVe"
},
"source": [
"## Download a Video Asset\n",
"\n",
"Now that we have our enviornment setup, lets download a video that we can detect objects in. Supervision comes with a great utility to help us hit the ground running. We can use the below snippet to he video is save a video asset in our local directory. It can also be accessed with the variable `path_to_video` for additional application logic."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "MyNzGpzOULVe"
},
"outputs": [],
"source": [
"from supervision.assets import download_assets, VideoAssets\n",
"\n",
"# Download a supervision video asset\n",
"path_to_video = download_assets(VideoAssets.PEOPLE_WALKING)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0cMveUy5U-tN"
},
"source": [
"<div style=\"display: flex; justify-content: center;\">\n",
" <video controls width=\"1000\"\">\n",
" <source\n",
" src=\"https://media.roboflow.com/supervision/video-examples/people-walking.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
" </video>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "lowrxifpULVe"
},
"source": [
"## Tracking Objects in a Frame\n",
"\n",
"Now that we have our video installed, let's get to work on tracking objects. We'll first pull in a model from roboflow Inference to detect people in our video. Then let's create a `byte_tracker` object that we'll pass our detections to. This will give us a `tracker_id`. We'll then utilize that tracker id to label our detections with a `label_annotator` to display the tracker id."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 560
},
"id": "gtbnWeT8ULVe",
"outputId": "0fbc468d-ea0d-4d23-a44f-1d50e37f95bf"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1200x1200 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
],
"source": [
"import supervision as sv\n",
"from inference.models.utils import get_roboflow_model\n",
"\n",
"# Load a pre trained yolov8 nano model from Roboflow Inference.\n",
"model = get_roboflow_model('yolov8n-640')\n",
"\n",
"# Create a video info object from the video path.\n",
"video_info = sv.VideoInfo.from_video_path(path_to_video)\n",
"\n",
"# Create a label annotator for labeling detections with our tracker_id.\n",
"label = sv.LabelAnnotator()\n",
"\n",
"# Create a ByteTrack object to track detections.\n",
"byte_tracker = sv.ByteTrack(frame_rate=video_info.fps)\n",
"\n",
"# Create a frame generator from video path for iteration of frames.\n",
"frame_generator = sv.get_video_frames_generator(path_to_video)\n",
"\n",
"# Grab a frame from the frame_generator.\n",
"frame = next(frame_generator)\n",
"\n",
"# Run inference on the frame by passing it to our model.\n",
"result = model.infer(frame)[0]\n",
"\n",
"# Convert model results to a supervision detection object.\n",
"detections = sv.Detections.from_inference(result)\n",
"\n",
"# Update detections with tracker ids fro byte_tracker.\n",
"tracked_detections = byte_tracker.update_with_detections(detections)\n",
"\n",
"# Create labels with tracker_id for label annotator.\n",
"labels = [ f\"{tracker_id}\" for tracker_id in tracked_detections.tracker_id ]\n",
"\n",
"# Apply label annotator to frame.\n",
"annotated_frame = label.annotate(scene=frame.copy(), detections=tracked_detections, labels=labels)\n",
"\n",
"# Display the frame.\n",
"sv.plot_image(annotated_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wR2nrNUiVOGq"
},
"source": [
"## Tracking Objects in a Video\n",
"\n",
"Finally, we'll use a utility called `VideoSink` to save the annotated frames to a video. Let's dive in to the code."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "b4lOhjcfVYAl"
},
"outputs": [],
"source": [
"from tqdm import tqdm\n",
"\n",
"# Load a pre trained yolov8 nano model from Roboflow Inference.\n",
"model = get_roboflow_model('yolov8n-640')\n",
"\n",
"# Create a video info object from the video path.\n",
"video_info = sv.VideoInfo.from_video_path(path_to_video)\n",
"\n",
"# Create a label annotator for labeling detections with our tracker_id.\n",
"label = sv.LabelAnnotator()\n",
"\n",
"# Create a ByteTrack object to track detections.\n",
"byte_tracker = sv.ByteTrack(frame_rate=video_info.fps)\n",
"\n",
"# Create a frame generator from video path for iteration of frames.\n",
"frame_generator = sv.get_video_frames_generator(path_to_video)\n",
"\n",
"# Create a video sink context manager to save resulting video.\n",
"with sv.VideoSink(target_path=\"output.mp4\", video_info=video_info) as sink:\n",
"\n",
" # Iterate through frames yielded from the frame_generator.\n",
" for frame in tqdm(frame_generator, total=video_info.total_frames):\n",
"\n",
" # Run inference on the frame by passing it to our model.\n",
" result = model.infer(frame)[0]\n",
"\n",
" # Convert model results to a supervision detection object.\n",
" detections = sv.Detections.from_inference(result)\n",
"\n",
" # Update detections with tracker ids fro byte_tracker.\n",
" tracked_detections = byte_tracker.update_with_detections(detections)\n",
"\n",
" # Create labels with tracker_id for label annotator.\n",
" labels = [ f\"{tracker_id}\" for tracker_id in tracked_detections.tracker_id ]\n",
"\n",
" # Apply label annotator to frame.\n",
" annotated_frame = label.annotate(scene=frame.copy(), detections=tracked_detections, labels=labels)\n",
"\n",
" # Save the annotated frame to an output video.\n",
" sink.write_frame(frame=annotated_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0J10FczGULVe"
},
"source": [
"Let's take a look at our resulting video. It will also be created in your current directory with the name `output.mp4` Notice how even with a little flicker, we can see the `tracker_id` on the people walking in the video. With trackers under your belt, there are now a wide variety of use cases you can solve for! Happy building!\n",
"\n",
"<div style=\"display: flex; justify-content: center;\">\n",
" <video controls width=\"1000\">\n",
" <source\n",
" src=\"https://media.roboflow.com/supervision/cookbooks/object-tracking.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
" </video>\n",
"</div>"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "V100",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
File diff suppressed because it is too large. Load diff
+1345
View File
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,894 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"gpuType": "T4"
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"source": [
"# Zero-Shot Object Detection with YOLO-World\n",
"---\n",
"[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/zero-shot-object-detection-with-yolo-world.ipynb)\n",
"[![Roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/what-is-yolo-world/)\n",
"[![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/AILab-CVC/YOLO-World)\n",
"[![arXiv](https://img.shields.io/badge/arXiv-2401.17270-b31b1b.svg)](https://arxiv.org/abs/2401.17270)\n",
"\n",
"Click the `Open in Colab` button to run the cookbook on Google Colab.\n",
"\n",
"<br>\n",
"\n",
"YOLO-World was designed to solve a limitation of existing zero-shot object detection models: speed. Whereas other state-of-the-art models use Transformers, a powerful but typically slower architecture, YOLO-World uses the faster CNN-based YOLO architecture.\n",
"\n",
"According to the paper YOLO-World reached between 35.4 AP with 52.0 FPS for the large version and 26.2 AP with 74.1 FPS for the small version. While the V100 is a powerful GPU, achieving such high FPS on any device is impressive.\n",
"\n",
"![visualization results of referring object detection](https://storage.googleapis.com/com-roboflow-marketing/supervision/cookbooks/yolo-world-visualization-results-of-referring-object-detection.png)"
],
"metadata": {
"id": "kR-PyK7YXPVZ"
}
},
{
"cell_type": "markdown",
"source": [
"## Before you start\n",
"\n",
"Let's make sure that we have access to GPU. We can use `nvidia-smi` command to do that. In case of any problems navigate to `Edit` -> `Notebook settings` -> `Hardware accelerator`, set it to `GPU`, and then click `Save`."
],
"metadata": {
"id": "T-lkdAZUY73s"
}
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mP1Bv5jBXNbw",
"outputId": "43cc5b50-9958-447d-f597-9ee510e52792"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Fri Feb 16 12:46:14 2024 \n",
"+---------------------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n",
"|-----------------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|=========================================+======================+======================|\n",
"| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 65C P8 13W / 70W | 0MiB / 15360MiB | 0% Default |\n",
"| | | N/A |\n",
"+-----------------------------------------+----------------------+----------------------+\n",
" \n",
"+---------------------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=======================================================================================|\n",
"| No running processes found |\n",
"+---------------------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!nvidia-smi"
]
},
{
"cell_type": "markdown",
"source": [
"**NOTE:** To make it easier for us to manage datasets, images and models we create a `HOME` constant."
],
"metadata": {
"id": "nySApmvdZDEd"
}
},
{
"cell_type": "code",
"source": [
"import os\n",
"HOME = os.getcwd()\n",
"print(HOME)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JGXqXrQfY2yo",
"outputId": "161ad18e-a296-4f27-b9c4-2c1fb68a2fc3"
},
"execution_count": 2,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"/content\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"## Install required packages\n",
"\n",
"In this guide, we utilize two Python packages: `inference`, for executing zero-shot object detection using YOLO-World, and `supervision`, for post-processing and visualizing the detected objects."
],
"metadata": {
"id": "h1jNp-i3ZL0D"
}
},
{
"cell_type": "code",
"source": [
"!pip install -q inference-gpu[yolo-world]==0.9.12rc1"
],
"metadata": {
"id": "zfc06V9QZFup"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"!pip install -q supervision==0.19.0rc3"
],
"metadata": {
"id": "44LZf5qb3bet"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Imports"
],
"metadata": {
"id": "dnEI8EOpalbe"
}
},
{
"cell_type": "code",
"source": [
"import cv2\n",
"import supervision as sv\n",
"\n",
"from tqdm import tqdm\n",
"from inference.models.yolo_world.yolo_world import YOLOWorld"
],
"metadata": {
"id": "UIcZyEhuacFT"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Download example data"
],
"metadata": {
"id": "ULzC4SZdbO-L"
}
},
{
"cell_type": "code",
"source": [
"!wget -P {HOME} -q https://media.roboflow.com/notebooks/examples/dog.jpeg\n",
"!wget -P {HOME} -q https://media.roboflow.com/supervision/cookbooks/yellow-filling.mp4"
],
"metadata": {
"id": "29c6jMS1a7NS"
},
"execution_count": 6,
"outputs": []
},
{
"cell_type": "code",
"source": [
"SOURCE_IMAGE_PATH = f\"{HOME}/dog.jpeg\"\n",
"SOURCE_VIDEO_PATH = f\"{HOME}/yellow-filling.mp4\""
],
"metadata": {
"id": "Kvq4jtTjg31-"
},
"execution_count": 7,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"**NOTE:** If you want to run the cookbook using your own file as input, simply upload video to Google Colab and replace `SOURCE_IMAGE_PATH` and `SOURCE_VIDEO_PATH` with the path to your file."
],
"metadata": {
"id": "M0_JmZ08gyYg"
}
},
{
"cell_type": "markdown",
"source": [
"## Run Object Detection\n",
"\n",
"The Inference package provides the YOLO-World model in three versions: `S`, `M`, and `L`. You can load them by defining model_id as `yolo_world/s`, `yolo_world/m`, and `yolo_world/l`, respectively. The `ROBOFLOW_API_KEY` is not required to utilize this model.\n",
"\n",
"\n",
"\n",
"\n",
"\n"
],
"metadata": {
"id": "NLP6DK4YbVpm"
}
},
{
"cell_type": "code",
"source": [
"model = YOLOWorld(model_id=\"yolo_world/l\")"
],
"metadata": {
"id": "osrplWqebju0"
},
"execution_count": 8,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"YOLO-World is a zero-shot model, enabling object detection without any training. You only need to define a prompt as a list of classes (things) you are searching for."
],
"metadata": {
"id": "vzZgYhZodzgS"
}
},
{
"cell_type": "code",
"source": [
"classes = [\"person\", \"backpack\", \"dog\", \"eye\", \"nose\", \"ear\", \"tongue\"]\n",
"model.set_classes(classes)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "UZTYuZlAdYhC",
"outputId": "89dba6b8-5f80-4802-fe85-27b4b5c66bb3"
},
"execution_count": 9,
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 338M/338M [00:03<00:00, 106MiB/s]\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"We perform detection on our sample image. Then, we convert the result into a [`sv.Detections`](https://supervision.roboflow.com/latest/detection/core/) object, which will be useful in the later parts of the cookbook."
],
"metadata": {
"id": "fXLWvBQNgoV_"
}
},
{
"cell_type": "code",
"source": [
"image = cv2.imread(SOURCE_IMAGE_PATH)\n",
"results = model.infer(image)\n",
"detections = sv.Detections.from_inference(results)"
],
"metadata": {
"id": "ZinEbFJsdp9m"
},
"execution_count": 10,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"The results we've obtained can be easily visualized with [`sv.BoundingBoxAnnotator`](https://supervision.roboflow.com/latest/annotators/#supervision.annotators.core.BoundingBoxAnnotator) and [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/annotators/#supervision.annotators.core.LabelAnnotator). We can adjust parameters such as line thickness, text scale, line and text color allowing for a highly tailored visualization experience."
],
"metadata": {
"id": "jiYw1EXzhpbu"
}
},
{
"cell_type": "code",
"source": [
"BOUNDING_BOX_ANNOTATOR = sv.BoundingBoxAnnotator(thickness=2)\n",
"LABEL_ANNOTATOR = sv.LabelAnnotator(text_thickness=2, text_scale=1, text_color=sv.Color.BLACK)"
],
"metadata": {
"id": "37CMTxw0jSyH"
},
"execution_count": 11,
"outputs": []
},
{
"cell_type": "code",
"source": [
"annotated_image = image.copy()\n",
"annotated_image = BOUNDING_BOX_ANNOTATOR.annotate(annotated_image, detections)\n",
"annotated_image = LABEL_ANNOTATOR.annotate(annotated_image, detections)\n",
"sv.plot_image(annotated_image, (10, 10))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 807
},
"id": "YkVoWxchher5",
"outputId": "ff1dce17-5584-496a-9113-e4d5123489b4"
},
"execution_count": 12,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Adjusting Confidence Level"
],
"metadata": {
"id": "KrferzhUnOk1"
}
},
{
"cell_type": "markdown",
"source": [
"Note that many classes from our prompt were not detected. This is because the default confidence threshold in Inference is set to `0.5`. Let's try significantly lowering this value. We've observed that the confidence returned by YOLO-World is significantly lower when querying for classes outside the [COCO](https://universe.roboflow.com/microsoft/coco) dataset."
],
"metadata": {
"id": "-aBRGrJnlvjN"
}
},
{
"cell_type": "code",
"source": [
"image = cv2.imread(SOURCE_IMAGE_PATH)\n",
"results = model.infer(image, confidence=0.003)\n",
"detections = sv.Detections.from_inference(results)"
],
"metadata": {
"id": "XKAJJQVLiE6y"
},
"execution_count": 13,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"By default, `sv.LabelAnnotator` displays only the names of objects. To also view the confidence levels associated with each detection, we must define custom `labels` and pass them to `sv.LabelAnnotator`."
],
"metadata": {
"id": "E2UGr46TmiaQ"
}
},
{
"cell_type": "code",
"source": [
"labels = [\n",
" f\"{classes[class_id]} {confidence:0.3f}\"\n",
" for class_id, confidence\n",
" in zip(detections.class_id, detections.confidence)\n",
"]\n",
"\n",
"annotated_image = image.copy()\n",
"annotated_image = BOUNDING_BOX_ANNOTATOR.annotate(annotated_image, detections)\n",
"annotated_image = LABEL_ANNOTATOR.annotate(annotated_image, detections, labels=labels)\n",
"sv.plot_image(annotated_image, (10, 10))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 807
},
"id": "Zw9tE3fKl4R3",
"outputId": "857333d8-7279-4a5c-9bb8-8be8584b82c2"
},
"execution_count": 14,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Using Non-Max Suppression (NMS) to Eliminate Double Detections\n",
"\n",
"To eliminate duplicates, we will use [Non-Max Suppression (NMS)](https://blog.roboflow.com/how-to-code-non-maximum-suppression-nms-in-plain-numpy). NMS evaluates the extent to which detections overlap using the Intersection over Union metric and, upon exceeding a defined threshold, treats them as duplicates. Duplicates are then discarded, starting with those of the lowest confidence. The value should be within the range `[0, 1]`. The smaller the value, the more restrictive the NMS.\n",
"\n",
"\n",
"\n",
"\n",
"\n"
],
"metadata": {
"id": "t88HE-7FofwJ"
}
},
{
"cell_type": "code",
"source": [
"image = cv2.imread(SOURCE_IMAGE_PATH)\n",
"results = model.infer(image, confidence=0.003)\n",
"detections = sv.Detections.from_inference(results).with_nms(threshold=0.1)"
],
"metadata": {
"id": "pyyjlCkAl9g6"
},
"execution_count": 15,
"outputs": []
},
{
"cell_type": "code",
"source": [
"labels = [\n",
" f\"{classes[class_id]} {confidence:0.3f}\"\n",
" for class_id, confidence\n",
" in zip(detections.class_id, detections.confidence)\n",
"]\n",
"\n",
"annotated_image = image.copy()\n",
"annotated_image = BOUNDING_BOX_ANNOTATOR.annotate(annotated_image, detections)\n",
"annotated_image = LABEL_ANNOTATOR.annotate(annotated_image, detections, labels=labels)\n",
"sv.plot_image(annotated_image, (10, 10))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 807
},
"id": "no-BoxjTpJt1",
"outputId": "30322755-e956-4093-e302-785258476849"
},
"execution_count": 16,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Video Processing"
],
"metadata": {
"id": "S-LLI26VvF7B"
}
},
{
"cell_type": "markdown",
"source": [
"The [`get_video_frames_generator`](https://supervision.roboflow.com/latest/utils/video/#supervision.utils.video.get_video_frames_generator) enables us to easily iterate over video frames. Let's create a video generator for our sample input file and display its first frame on the screen."
],
"metadata": {
"id": "E0rhepjGv9oe"
}
},
{
"cell_type": "code",
"source": [
"generator = sv.get_video_frames_generator(SOURCE_VIDEO_PATH)\n",
"frame = next(generator)\n",
"\n",
"sv.plot_image(frame, (10, 10))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 472
},
"id": "J2Tm9lcGpLF1",
"outputId": "94629d68-9266-474e-e311-cd311457816f"
},
"execution_count": 17,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"Let's update our list of classes. This time we are looking for `yellow filling`. The rest of the code performing detection, filtering and visualization remains unchanged."
],
"metadata": {
"id": "Su3lwi6D62sR"
}
},
{
"cell_type": "code",
"source": [
"classes = [\"yellow filling\"]\n",
"model.set_classes(classes)"
],
"metadata": {
"id": "bddF-z6WwAkD"
},
"execution_count": 23,
"outputs": []
},
{
"cell_type": "code",
"source": [
"results = model.infer(frame, confidence=0.002)\n",
"detections = sv.Detections.from_inference(results).with_nms(threshold=0.1)"
],
"metadata": {
"id": "xQ0kV9huwmoM"
},
"execution_count": 38,
"outputs": []
},
{
"cell_type": "code",
"source": [
"annotated_image = frame.copy()\n",
"annotated_image = BOUNDING_BOX_ANNOTATOR.annotate(annotated_image, detections)\n",
"annotated_image = LABEL_ANNOTATOR.annotate(annotated_image, detections)\n",
"sv.plot_image(annotated_image, (10, 10))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 472
},
"id": "AfWCMuq5wsuY",
"outputId": "2a1ede5e-8e19-4d65-90a7-4579f0115183"
},
"execution_count": 39,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
],
"image/png": "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 truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Filtering Detectuions by Area"
],
"metadata": {
"id": "CwI09wuYCztj"
}
},
{
"cell_type": "markdown",
"source": [
"Our prompt allowed us to locate all filled holes, but we also accidentally marked the entire high-level element. To address this issue, we'll filter detections based on their relative area in relation to the entire video frame. If a detection occupies more than 10% of the frame's total area, it will be discarded."
],
"metadata": {
"id": "TVAulRgE-idz"
}
},
{
"cell_type": "markdown",
"source": [
"We can use [`VideoInfo.from_video_path`](https://supervision.roboflow.com/develop/utils/video/#supervision.utils.video.VideoInfo) to learn basic information about our video, such as duration, resolution, or FPS."
],
"metadata": {
"id": "OX4l0ofl_Pe4"
}
},
{
"cell_type": "code",
"source": [
"video_info = sv.VideoInfo.from_video_path(SOURCE_VIDEO_PATH)\n",
"video_info"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LV99lGQJ_JzT",
"outputId": "0683435f-a3cb-418f-b1b9-f94d299192f3"
},
"execution_count": 40,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"VideoInfo(width=1280, height=720, fps=25, total_frames=442)"
]
},
"metadata": {},
"execution_count": 40
}
]
},
{
"cell_type": "markdown",
"source": [
"Knowing the frame's resolution allows us to easily calculate its total area, expressed in pixels."
],
"metadata": {
"id": "IGckLMVR_4kp"
}
},
{
"cell_type": "code",
"source": [
"width, height = video_info.resolution_wh\n",
"frame_area = width * height\n",
"frame_area"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8aJBl-Rc_xUP",
"outputId": "c4b2798b-c5c6-429c-8886-02b4f7af3924"
},
"execution_count": 41,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"921600"
]
},
"metadata": {},
"execution_count": 41
}
]
},
{
"cell_type": "markdown",
"source": [
"On the other hand, by using [`sv.Detections.area`](https://supervision.roboflow.com/develop/detection/core/#supervision.detection.core.Detections.area) property, we can learn the area of each individual bounding box."
],
"metadata": {
"id": "Y_LO4ODXAntj"
}
},
{
"cell_type": "code",
"source": [
"results = model.infer(frame, confidence=0.002)\n",
"detections = sv.Detections.from_inference(results).with_nms(threshold=0.1)\n",
"detections.area"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "B9PQhXf__TNW",
"outputId": "dc096dd6-a93d-4599-e6d8-9d475a54b999"
},
"execution_count": 45,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([ 7.5408e+05, 92844, 11255, 12969, 9875.9, 8007.7, 5433.5])"
]
},
"metadata": {},
"execution_count": 45
}
]
},
{
"cell_type": "markdown",
"source": [
"Now, we can combine these two pieces of information to construct a filtering condition for detections with an area greater than 10% of the entire frame."
],
"metadata": {
"id": "LAnsLumrBZNw"
}
},
{
"cell_type": "code",
"source": [
"(detections.area / frame_area) < 0.10"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lD9ONsS9BRov",
"outputId": "100d1d15-eba3-47ed-823b-b8756e13c123"
},
"execution_count": 46,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([False, False, True, True, True, True, True])"
]
},
"metadata": {},
"execution_count": 46
}
]
},
{
"cell_type": "code",
"source": [
"detections = detections[(detections.area / frame_area) < 0.10]\n",
"\n",
"annotated_image = frame.copy()\n",
"annotated_image = BOUNDING_BOX_ANNOTATOR.annotate(annotated_image, detections)\n",
"annotated_image = LABEL_ANNOTATOR.annotate(annotated_image, detections)\n",
"sv.plot_image(annotated_image, (10, 10))"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 472
},
"id": "XzE7wjwE_bOR",
"outputId": "5df62911-a001-46a4-a16c-8cdab7608e2e"
},
"execution_count": 47,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
],
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxoAAAHHCAYAAAA4fy6KAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9S5Mku7Iuhn0ORGZWVb/WWnuffc7l5RE54EBmGsjEv8ABBxzod2kkM/00DWQmGe3y8ornufd6dHdVZWZEwF0DdwccEZFZWb16H11eK7RVZ2YEAoGHw/E5/AESEcFbektv6S29pbf0lt7SW3pLb+ktfceU/v9dgbf0lt7SW3pLb+ktvaW39Jbe0n956U3QeEtv6S29pbf0lt7SW3pLb+ktfff0Jmi8pbf0lt7SW3pLb+ktvaW39Ja+e3oTNN7SW3pLb+ktvaW39Jbe0lt6S989vQkab+ktvaW39Jbe0lt6S2/pLb2l757eBI239Jbe0lt6S2/pLb2lt/SW3tJ3T2+Cxlt6S2/pLb2lt/SW3tJbektv6bunN0HjLb2lt/SW3tJbektv6S29pbf03dNwa8b/8f/yfwARIaWElDNSykh5h93ugN1wh2G3R84ZSASIoPAZpZxRphFSJtA8AphBYBAxiAQpaXmgBCKCnhxIAAABIAIw2599n1kwzgXjWHAeZ0wzYyyCcWbMMyBMYAFEBCwCEYEfSSgACjOYGVIKAAERkIhARAARQAl52GF/eMD93Xv84Q9/wp/+9N/hj3/8b3F3+ARIQkqCIQN5AIACyAzhgkSEnACiAnDBNP2Gv/z8v+Avf/5P4NNvGBKQCUgZoAR9J7TLrMVWX/0rpYCZwWwNYAJAek0AFoIIgUH1Gc4fcP+H/xM+/Tf/E+7++/8R7/+PP+Dhh4RMMwYm3E0Aef+waF+IgDlBsMMv9wlf9oTTAJyHVqdaQ0oACOL9FZKWw5hKwUkET8z4ysBvQjjC3lUEMs3AaYKMs/7NBTQV0FwAFpA2DlwKIAwSJQASHbtIJTyPkOdfIcfPkOdfIOefIdMv+PHpz/jx6xf8+PP/B3fPf8Z+v8eHDx/w8dN7PDzcY7cbsN/vcDjsMQxJx8XGgYgAIeTpHuMf/wdM//3/FX/+23+Hz/eMMtj4ESFTwpASEiUgEUYpOE+C55nxmwj+nAT/mATnseBwZKSpgOdS+yExICwQGwMCMIDwkRL+hoGfJCOx4F9ywVhmHCbB+5mwI8I5MZhnMDNmCCYIJjBOzHiUhIkBZgHZROLwjjqeIiBmkAhIrB5cAJ6R5glcJpR5xswFcykgMA5g3B2/Al++IH15xI804O9//BF//+kDfni4w7Db6TwmHyGCJIKkhAJgJoHA6YYAAVhY5ybZnB1nyDyB5xnCglIYXBKmAswQzETW5gEM0ueFAS7aJoK2Cdomn+80zyBhu6ZzNIm2l6YTaDoiTUfsnj9Dnv+CdPwHyPHPkPGIJFlrbO2qUzZ8khAIZHfDTZsqKSUk6xqC/qZkvE8AtvJJmYP2k/EmWsy1WhcbU62PcVCya/4fESRbOfbOlDMI/n6tA1JCykN7nz8r+gYy/iiUIZQgKYMzAWkAKAPIoJTrs0LJ+IS+q/F38aG337oGeHdJ6D0gtpsWv63J4chZCfR9Oa37cv0eK6/2+8Yz3Wu2ygxZpc++Vcc6LzfGejutefC1rBfrdqEe23nopaZu0mp3vY7ZNl2/NkkkgmvFXenzcEV5JnpeuZU8H3ClzfH7i029TrcRx7yc8YX+ENnsj+36tPIu0224/kI7bzkjmjoGe0veq2/cbGscM/1+Aw0t6nSZfq/QTX1miXj7+/GTEqGxZMXNzqfbHza/r9+/VafwKct74QGKefXL//3/9v+42FZPNwsatZEAIAJBgQhQWJCKgmtmavdlArMKGcIzQDOSzF1nxQWNaiv7RlWVCxMkAQmClASJxIQUgUBBlLCAJdkckgp8ARVUfBFi5gB1Yj1s4U2ERABzwel8xDw/Y5qfsN/fIdHOnkz2tJarjxcQCQQTCo+Y5iPm+QTmM4BJF2yi+iwkTqheyHBgqH8MCLV2sYT26Ccb4+BSMJ7OOD4/gZ+fsDvf444PyDksnouxdTHi6x543APjAAgBmVW2sdr1Y2PjHMtw4Y5rG+xPqNZbmMFFpUcpCvpgn+RCRmCCIt7LaO8Xqw8XcJnBZQbmGXkuyGMBn2YMT2cMz2fQVACQCYEJwzBgyBm7YcBuGJBzRk4EhXUMQRNMjwPh8IdPOL7b47gTnAcg+30TjJkFSIoSGQIWxpkERzBGEaRJsB/F2rhAUbKApAIIeR8qAE8MHIpgFsbIjGcQDiDty0AvOguUDoSVXuBCdsgLWxylEo9d9zw2BrVcFlARDEWQRLArMw6nGWkW/LB7wH97/xF/+uFHvLvLSEMCr6iKKm1433KlJaMJoy6GoAhDigqfXIrSOgsKU6V16TquTQSvr5IJ1/nAzJB5BnEBSjFBY0YqE6icQOUMjE/A+Ixy/go6/jPw/Bl0+ox0ngHOkIR+sBaTibYuhoWEjMcpr5Ge71imnhdR3YABthe0ykPDRkC97gJzEDauCS3rZMtfbG+tWyszUbIxvoZkfYTJPmtNW8dJo5ctVrNd7g15fm/6t3jHIm2R2XauV6RrBd5c1HUho/LpjfGj1bh+HyEDQBXUDflfqBuUZitYDwKChN8gLUd0FLyOEoSKWCi90HmxyS8NwS2k9jpyfCG3bVR8HyL3FnyvCfPXnXgddn4VGdIr819+r5ZWS+0udEIGgI5nvpgC1S27Ma6by2t0rXxpOB0SkO9t6WZBY5d8oQKIGAAh2U4oM1DmCXE/jzCDeARJ0T8qtmMM0yJ4J9rAUUIKo6CwT4GuS2hJCEK640BZkDgjFbH6oGMk3mFEVDUCDp7aop+QEyElZ3q2eMJ2t2XCPB9xOj3idPqK/XCP/f7edgAzSJQp1VozwJgxlyPm6YTz6Qum8yOkjCAUEDJ8VEka0bUdZv+T+sls4IwZ4mBLABGq4MwBr4ig8AR5/g1PX/8jypd/wMPXT+Af7iGZrV8jSxAIAQVAycCXg+CcbWeZDPRCDPzC4ITWNYn2seNVwDROEMwARgATBEUAYUIuCmCZRQWMwkApyDNDZg5A3Jk8UMVMcfhqQpoUUCmgMkHOJ+D8FTx9AZdnEI/I8xnD+Qvk/DOonDGIYCDBYSDcDwmHgbDLwC4JdmAkEEhMw2XtY8ko5SPK+7/H4/0djgOjwHadQUhCKAAyCIm1WmcAowBnEfve2p84gdgEJ4HtuHP9DRvvAqBAP2dhm0mM58SYUDACeMcJO5UgwKLarSJAIYJw0oEwVC5sg81k0rbUdgpQBTty1aG40K7CX2JGKgVSZkAKhumMdzzjYRjwp8Mef/r4ER8eDqAkKDpj++0RYgiSCk6I2rEgOLsQwqq94rmgcLG2CQpENRe2yy82VxPENGCq0aj1Fq2HCJuwUlSDWWZgnkBlxFBG0HwGzSfQ/AwcPwOnz0jnL0inf4acTirwuMbAaLLO9YWAUT8XO2d1B6rbaUpB22DgOnBPMg2Zaza8Py8uMQ4YXOjwBSMIBAQvx75LKzfOLSGCIAV+aHPQ6qQazaSfrnmp7cCiPNJRqvM5dJpfqwtc5Exe2LJ+yx6gqp2NuZpAs9lZV64t7pmG6nvBMKAXBptwFa7hFjnrQn1Dek2dSfr8WyCiQgyfBy+hrYhjYt7WWPxe0PZNqeK51v8uMFTOtAm6lqPSj92117U827lbnmt0G9NLAlXIeaW4W98W39swy8a1G0v5vZqdWk7975Z8GzT9LcJGLw+8Lm08uypHGi5eXu++bA7sRq2WwrfQOlvHetv60aFx59H18Ze5VEw3Cxr7nYHkyuOMSYiAzHTIr4OAJIyEAkJBmLkOFW3x9ey6EMdF1XfJvN2JXIXPqtHIKmT4Z06AmDmSg3EVgnQHUUTfW3cuTOBIKYIA3XlPOSMnIBGDMOHp6S+4u3tAThnAR+S7A4BBF2RF+QpqeIbwGdP8hHk64vj8FafjE3ieMISdxDZQ/mH7fHWHOgoZrt1A1SAJJxMy9BoLW14GzzPm8hnT5/+E8vmf8P7zf4fyd4DctQVT6spiQgQJCghjtnsg3RBH2KMIszrBwbEJOeLAUXfVZwATgMmERWJSsxIDtFRMsCiCNCtYFLZ3VVASP3XkWoVUSME4gs4n0PkRND1CyhFSRgzziP34hDQ9IvERmSbs0g77TPqXgEyCjKL0xYQEBgWhsSDj7v7vML3/W3zZJ5wGqQBXoIJoBsD+DAtGCM4iOEH/ZgNMiVHNahSwJoiwfY/LUBMwZgZmSYAIRhIcM2OUAgiwZ0a2ucDMmAWYKbU+TwCXKlNo3wZtir/VNwqqXaIJF2CVTkTEBA3XCEy44wl/GAb86eEdfry7w/3dAZxYF+qKD30BN1oSu2fvYgPF1cTRK8tSx1a4CRkq4EndfBBjJySMZBo/F4xcA8hSIDKrORW7lmRCms+gckaejqD5BJwfIeMj6PlnpOOvSOMj8nSE8FQ1KHXeivG9hZDhqfJo/03S+FwoBx2vS1VLIGI8IqmJk4L7K250Uv9D3W2qQvliCnV1iAuZ39Q/kQRJCa5dUS0vVaHCdMqVz7sJZdNqNIGAbOyX9Wy/KaCs8Ezsq6ttx0Lj2eDfSzvNfQddfcUNJb2cY7NG5PV/fbqqQVrU6BbYti5tg+62ANANBS+fobDGf68U5LYXUnvr8v3118ZOv2ODmHtTHtl4XytmO+NC3LxcVJAIb6LcG2iLrjYggtpeKHHs13K+bjSvDdXWPPk++YzHXHrwhgbQ6sttqV8X7EtliRXlh1wS1guntpdeHPNcyn9V8gxfpa0pG1leq428XaOx39mcWVS09oUvcGbbSLqrqItfy9gUB22HL7nQ0loBgHSnGQASVbMstWtW8ylK6i+Rc0bOClqIXUgBiLine truncated
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"## Final Result"
],
"metadata": {
"id": "7SjPoFnLC9aI"
}
},
{
"cell_type": "markdown",
"source": [
"Finally, we are ready to process our entire video. Now in truth we can appreciate the speed of YOLO-World."
],
"metadata": {
"id": "WxwNMXGECodq"
}
},
{
"cell_type": "code",
"source": [
"TARGET_VIDEO_PATH = f\"{HOME}/yellow-filling-output.mp4\""
],
"metadata": {
"id": "p0aooVpaCSH3"
},
"execution_count": 49,
"outputs": []
},
{
"cell_type": "code",
"source": [
"frame_generator = sv.get_video_frames_generator(SOURCE_VIDEO_PATH)\n",
"video_info = sv.VideoInfo.from_video_path(SOURCE_VIDEO_PATH)\n",
"\n",
"width, height = video_info.resolution_wh\n",
"frame_area = width * height\n",
"frame_area\n",
"\n",
"with sv.VideoSink(target_path=TARGET_VIDEO_PATH, video_info=video_info) as sink:\n",
" for frame in tqdm(frame_generator, total=video_info.total_frames):\n",
" results = model.infer(frame, confidence=0.002)\n",
" detections = sv.Detections.from_inference(results).with_nms(threshold=0.1)\n",
" detections = detections[(detections.area / frame_area) < 0.10]\n",
"\n",
" annotated_frame = frame.copy()\n",
" annotated_frame = BOUNDING_BOX_ANNOTATOR.annotate(annotated_frame, detections)\n",
" annotated_frame = LABEL_ANNOTATOR.annotate(annotated_frame, detections)\n",
" sink.write_frame(annotated_frame)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "A8TzekpEwtTO",
"outputId": "cf71b8e7-00af-4b7b-c912-9157ced6b6c4"
},
"execution_count": 50,
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 442/442 [00:31<00:00, 13.90it/s]\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
" Keep in mind that the video preview below works only in the web version of the cookbooks and not in Google Colab.\n",
"\n",
"<video controls>\n",
" <source\n",
" src=\"https://storage.googleapis.com/com-roboflow-marketing/supervision/cookbooks/yellow-filling-output-1280x720.mp4\"\n",
" type=\"video/mp4\"\n",
" >\n",
"</video>"
],
"metadata": {
"id": "vMp9mSj1DGJ9"
}
}
]
}
+107
View File
@@ -0,0 +1,107 @@
.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(3, minmax(0, 1fr));
}
}
.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 */
}
+27
View File
@@ -1,4 +1,31 @@
:root {
/* Default to light theme */
--md-primary-fg-color: #8315F9;
--md-accent-fg-color: #00FFCE;
}
body.light {
/* Light theme */
--md-text-color: #000000;
--md-h2-color: #000000;
}
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%;
}
+25
View File
@@ -0,0 +1,25 @@
{% 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">
<p class="card repo-card" data-url="/develop/notebooks/quickstart" data-name="Supervision Quickstart" data-labels="ANNOTATOR,DETECTION,SAM" data-version="v0.18.0" data-author="SkalskiP,onuralpszr"></p>
<p class="card repo-card" data-url="/develop/notebooks/count-objects-crossing-the-line" data-name="Count Objects Crossing the Line" data-labels="ANNOTATORS,LINE ZONE,TRACKING" data-version="v0.18.0" data-author="SkalskiP"></p>
<p class="card repo-card" data-url="/develop/notebooks/zero-shot-object-detection-with-yolo-world" data-name="Zero-Shot Object Detection with YOLO-World" data-labels="ANNOTATORS,DETECTION,INFERENCE" data-version="v0.19.0" data-author="SkalskiP"></p>
<p class="card repo-card" data-url="/develop/notebooks/download-supervision-assets" data-name="Downloading Supervision Assets" data-labels="ASSETS" data-version="v0.18.0" data-author="nickherrig"></p>
<p class="card repo-card" data-url="/develop/notebooks/annotate-video-with-detections" data-name="Annotate Video with Detections" data-labels="INFERENCE,YOLOV8" data-version="v0.18.0" data-author="nickherrig"></p>
<p class="card repo-card" data-url="/develop/notebooks/object-tracking" data-name="Object Tracking" data-labels="TRACKING, ANNOTATOR" data-version="v0.18.0" data-author="nickherrig"></p>
<p class="card repo-card" data-url="/develop/notebooks/occupancy_analytics" data-name="Analyzing Zone Occupancy" data-labels="ANNOTATOR,DETECTION,ZONES" data-version="v0.19.0" data-author="stellasphere"></p>
<p class="card repo-card" data-url="/develop/notebooks/evaluating-alignment-of-text-to-image-diffusion-models" data-name="Evaluating Alignment of Text-to-image Diffusion Models" data-labels="ANNOTATORS,YOLO WORLD" data-version="v0.19.0rc5" data-author="iamhatesz"></p>
</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 %}
+17
View File
@@ -0,0 +1,17 @@
{% extends "base.html" %}
{% block content %}
{% if page.nb_url %}
<style>
.md-sidebar--primary {
display: none;
}
</style>
{% endif %}
{{ super() }}
{% endblock content %}
{% block extrahead %}
<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 %}
+6 -1
View File
@@ -1,3 +1,8 @@
## ByteTrack
---
comments: true
status: new
---
# ByteTrack
:::supervision.tracker.byte_tracker.core.ByteTrack
+9 -1
View File
@@ -1,3 +1,11 @@
## list_files_with_extensions
---
comments: true
---
# File Utils
<div class="md-typeset">
<h2>list_files_with_extensions</h2>
</div>
:::supervision.utils.file.list_files_with_extensions
+31 -2
View File
@@ -1,7 +1,36 @@
## ImageSink
---
comments: true
status: new
---
# Image Utils
<div class="md-typeset">
<h2>ImageSink</h2>
</div>
:::supervision.utils.image.ImageSink
## crop
<div class="md-typeset">
<h2>crop_image</h2>
</div>
:::supervision.utils.image.crop_image
<div class="md-typeset">
<h2>letterbox_image</h2>
</div>
:::supervision.utils.image.letterbox_image
<div class="md-typeset">
<h2>resize_image</h2>
</div>
:::supervision.utils.image.resize_image
<div class="md-typeset">
<h2>place_image</h2>
</div>
:::supervision.utils.image.place_image
+18
View File
@@ -0,0 +1,18 @@
---
comments: true
status: new
---
# Iterables Utils
<div class="md-typeset">
<h2>create_batches</h2>
</div>
:::supervision.utils.iterables.create_batches
<div class="md-typeset">
<h2>fill</h2>
</div>
:::supervision.utils.iterables.fill
+13 -2
View File
@@ -1,7 +1,18 @@
## plot_image
---
comments: true
---
# Notebooks Utils
<div class="md-typeset">
<h2>plot_image</h2>
</div>
:::supervision.utils.notebook.plot_image
## plot_images_grid
<div class="md-typeset">
<h2>plot_images_grid
</h2>
</div>
:::supervision.utils.notebook.plot_images_grid
+21 -5
View File
@@ -1,19 +1,35 @@
## VideoInfo
---
comments: true
---
# Video Utils
<div class="md-typeset">
<h2>VideoInfo</h2>
</div>
:::supervision.utils.video.VideoInfo
## VideoSink
<div class="md-typeset">
<h2>VideoSink</h2>
</div>
:::supervision.utils.video.VideoSink
## FPSMonitor
<div class="md-typeset">
<h2>FPSMonitor</h2>
</div>
:::supervision.utils.video.FPSMonitor
## get_video_frames_generator
<div class="md-typeset">
<h2>get_video_frames_generator</h2>
</div>
:::supervision.utils.video.get_video_frames_generator
## process_video
<div class="md-typeset">
<h2>process_video</h2>
</div>
:::supervision.utils.video.process_video
+32
View File
@@ -0,0 +1,32 @@
# Examples
This repository is packed with real-world use-cases, provided through Python scripts or
interactive notebooks. Browse through to understand how the Supervision library
interfaces with diverse applications.
- [tracking](./tracking) by [@SkalskiP](https://github.com/SkalskiP)
- [count people in zone](./count_people_in_zone) by [@SkalskiP](https://github.com/SkalskiP)
- [traffic analysis](./traffic_analysis) by [@SkalskiP](https://github.com/SkalskiP)
- [speed estimation](./speed_estimation) by [@SkalskiP](https://github.com/SkalskiP)
- [time in zone](./time_in_zone) by [@SkalskiP](https://github.com/SkalskiP)
- [heatmap and track](./heatmap_and_track/) by [@HinePo](https://github.com/HinePo)
## Contributing
We welcome contributions from the community in the form of examples, applications, and
guides. To contribute, please follow these steps:
1. Create a pull request (PR) with the `[Example]` prefix in the title, adding your
project folder to the `examples/` directory in the repository.
2. Confirm your project aligns with the following standards:
- Incorporates the `supervision` package.
- Provides a `README.md` file, detailing the instructions to execute the project.
- Showcases visual results, demonstrating the app's functionality.
- Avoids adding large assets or dependencies unless absolutely necessary.
- The contributor is expected to provide support for issues related to their
examples.
- In case the presented model has licensing complications, kindly specify them to
circumvent potential misunderstandings.
For inquiries or concerns about these prerequisites, feel free to raise a PR. We are
committed to assist and guide you.
+13
View File
@@ -0,0 +1,13 @@
# Ignore everything in the data directory
data/*
# But re-include all .json files
!data/*.json
*.pt
*.pth
*.mp4
*.mov
*.png
*.jpg
*.jpeg
+120
View File
@@ -0,0 +1,120 @@
# count people in zone
## 👋 hello
This demo is a video analysis tool that counts and highlights objects in specific zones
of a video. Each zone and the objects within it are marked in different colors, making
it easy to see and count the objects in each area. The tool can save this enhanced
video or display it live on the screen.
https://github.com/roboflow/supervision/assets/26109316/f84db7b5-79e2-4142-a1da-64daa43ce667
## 💻 install
- clone repository and navigate to example directory
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/count_people_in_zone
```
- setup python environment and activate it [optional]
```bash
python3 -m venv venv
source venv/bin/activate
```
- install required dependencies
```bash
pip install -r requirements.txt
```
- download `traffic_analysis.pt` and `traffic_analysis.mov` files
```bash
./setup.sh
```
## 🛠️ script arguments
- ultralytics
- `--source_weights_path` (optional): The path to the YOLO model's weights file.
Defaults to `"yolov8x.pt"` if not specified.
- `--zone_configuration_path`: Specifies the path to the JSON file containing zone
configurations. This file defines the polygonal areas in the video where objects will
be counted.
- `--source_video_path`: The path to the source video file that will be analyzed.
- `--target_video_path` (optional): The path to save the output video with annotations.
If not provided, the processed video will be displayed in real-time.
- `--confidence_threshold` (optional): Sets the confidence threshold for the YOLO model
to filter detections. Default is `0.3`.
- `--iou_threshold` (optional): Specifies the IOU (Intersection Over Union) threshold
for the model. Default is `0.7`.
- inference
- `--roboflow_api_key` (optional): The API key for Roboflow services. If not provided
directly, the script tries to fetch it from the `ROBOFLOW_API_KEY` environment
variable. Follow [this guide](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key)
to acquire your `API KEY`.
- `--model_id` (optional): Designates the Roboflow model ID to be used. The default
value is `"yolov8x-1280"`.
- `--zone_configuration_path`: Specifies the path to the JSON file containing zone
configurations. This file defines the polygonal areas in the video where objects will
be counted.
- `--source_video_path`: The path to the source video file that will be analyzed.
- `--target_video_path` (optional): The path to save the output video with annotations.
If not provided, the processed video will be displayed in real-time.
- `--confidence_threshold` (optional): Sets the confidence threshold for the YOLO model
to filter detections. Default is `0.3`.
- `--iou_threshold` (optional): Specifies the IOU (Intersection Over Union) threshold
for the model. Default is `0.7`.
## 📌 zone configuration
- `horizontal-zone-config.json`: Defines zones divided horizontally across the frame.
- `multi-zone-config.json`: Configures multiple zones with custom shapes and positions.
- `quarters-zone-config.json`: Splits the frame into four equal quarters.
- `vertical-zone-config.json`: Divides the frame into vertical zones of equal width.
## ⚙️ run example
- ultralytics
```bash
python ultralytics_example.py \
--zone_configuration_path data/multi-zone-config.json \
--source_video_path data/market-square.mp4 \
--confidence_threshold 0.3 \
--iou_threshold 0.5
```
- inference
```bash
python inference_example.py \
--roboflow_api_key <ROBOFLOW API KEY> \
--zone_configuration_path data/multi-zone-config.json \
--source_video_path data/market-square.mp4 \
--confidence_threshold 0.3 \
--iou_threshold 0.5
```
## © license
This demo integrates two main components, each with its own licensing:
- ultralytics: The object detection model used in this demo, YOLOv8, is distributed
under the [AGPL-3.0 license](https://github.com/ultralytics/ultralytics/blob/main/LICENSE).
You can find more details about this license here.
- supervision: The analytics code that powers the zone-based analysis in this demo is
based on the Supervision library, which is licensed under the
[MIT license](https://github.com/roboflow/supervision/blob/develop/LICENSE.md). This
makes the Supervision part of the code fully open source and freely usable in your
projects.
@@ -0,0 +1,76 @@
{
"polygons": [
[
[
0,
0
],
[
2160,
0
],
[
2160,
960
],
[
0,
960
]
],
[
[
0,
960
],
[
2160,
960
],
[
2160,
1920
],
[
0,
1920
]
],
[
[
0,
1920
],
[
2160,
1920
],
[
2160,
2880
],
[
0,
2880
]
],
[
[
0,
2880
],
[
2160,
2880
],
[
2160,
3840
],
[
0,
3840
]
]
]
}
@@ -0,0 +1,122 @@
{
"polygons": [
[
[
540,
985
],
[
1620,
985
],
[
2160,
1920
],
[
1620,
2855
],
[
540,
2855
],
[
0,
1920
]
],
[
[
0,
1920
],
[
540,
985
],
[
0,
0
]
],
[
[
1620,
985
],
[
2160,
1920
],
[
2160,
0
]
],
[
[
540,
985
],
[
0,
0
],
[
2160,
0
],
[
1620,
985
]
],
[
[
0,
1920
],
[
0,
3840
],
[
540,
2855
]
],
[
[
2160,
1920
],
[
1620,
2855
],
[
2160,
3840
]
],
[
[
1620,
2855
],
[
540,
2855
],
[
0,
3840
],
[
2160,
3840
]
]
]
}
@@ -0,0 +1,76 @@
{
"polygons": [
[
[
0,
0
],
[
1080,
0
],
[
1080,
1920
],
[
0,
1920
]
],
[
[
1080,
0
],
[
2160,
0
],
[
2160,
1920
],
[
1080,
1920
]
],
[
[
0,
1920
],
[
1080,
1920
],
[
1080,
3840
],
[
0,
3840
]
],
[
[
1080,
1920
],
[
2160,
1920
],
[
2160,
3840
],
[
1080,
3840
]
]
]
}
@@ -0,0 +1,76 @@
{
"polygons": [
[
[
0,
0
],
[
540,
0
],
[
540,
3840
],
[
0,
3840
]
],
[
[
540,
0
],
[
1080,
0
],
[
1080,
3840
],
[
540,
3840
]
],
[
[
1080,
0
],
[
1620,
0
],
[
1620,
3840
],
[
1080,
3840
]
],
[
[
1620,
0
],
[
2160,
0
],
[
2160,
3840
],
[
1620,
3840
]
]
]
}
@@ -0,0 +1,224 @@
import argparse
import json
import os
from typing import List, Tuple
import cv2
import numpy as np
from inference.core.models.roboflow import RoboflowInferenceModel
from inference.models.utils import get_roboflow_model
from tqdm import tqdm
import supervision as sv
COLORS = sv.ColorPalette.default()
def load_zones_config(file_path: str) -> List[np.ndarray]:
"""
Load polygon zone configurations from a JSON file.
This function reads a JSON file which contains polygon coordinates, and
converts them into a list of NumPy arrays. Each polygon is represented as
a NumPy array of coordinates.
Args:
file_path (str): The path to the JSON configuration file.
Returns:
List[np.ndarray]: A list of polygons, each represented as a NumPy array.
"""
with open(file_path, "r") as file:
data = json.load(file)
return [np.array(polygon, np.int32) for polygon in data["polygons"]]
def initiate_annotators(
polygons: List[np.ndarray], resolution_wh: Tuple[int, int]
) -> Tuple[
List[sv.PolygonZone], List[sv.PolygonZoneAnnotator], List[sv.BoundingBoxAnnotator]
]:
line_thickness = sv.calculate_dynamic_line_thickness(resolution_wh=resolution_wh)
text_scale = sv.calculate_dynamic_text_scale(resolution_wh=resolution_wh)
zones = []
zone_annotators = []
box_annotators = []
for index, polygon in enumerate(polygons):
zone = sv.PolygonZone(polygon=polygon, frame_resolution_wh=resolution_wh)
zone_annotator = sv.PolygonZoneAnnotator(
zone=zone,
color=COLORS.by_idx(index),
thickness=line_thickness,
text_thickness=line_thickness * 2,
text_scale=text_scale * 2,
)
box_annotator = sv.BoundingBoxAnnotator(
color=COLORS.by_idx(index), thickness=line_thickness
)
zones.append(zone)
zone_annotators.append(zone_annotator)
box_annotators.append(box_annotator)
return zones, zone_annotators, box_annotators
def detect(
frame: np.ndarray, model: RoboflowInferenceModel, confidence_threshold: float = 0.5
) -> sv.Detections:
"""
Detect objects in a frame using Inference model, filtering detections by class ID
and confidence threshold.
Args:
frame (np.ndarray): The frame to process, expected to be a NumPy array.
model (RoboflowInferenceModel): The Inference model used for processing the
frame.
confidence_threshold (float, optional): The confidence threshold for filtering
detections. Default is 0.5.
Returns:
sv.Detections: Filtered detections after processing the frame with the Inference
model.
Note:
This function is specifically tailored for an Inference model and assumes class
ID 0 for filtering.
"""
results = model.infer(frame)[0]
detections = sv.Detections.from_inference(results)
filter_by_class = detections.class_id == 0
filter_by_confidence = detections.confidence > confidence_threshold
return detections[filter_by_class & filter_by_confidence]
def annotate(
frame: np.ndarray,
zones: List[sv.PolygonZone],
zone_annotators: List[sv.PolygonZoneAnnotator],
box_annotators: List[sv.BoundingBoxAnnotator],
detections: sv.Detections,
) -> np.ndarray:
"""
Annotate a frame with zone and box annotations based on given detections.
Args:
frame (np.ndarray): The original frame to be annotated.
zones (List[sv.PolygonZone]): A list of polygon zones used for detection.
zone_annotators (List[sv.PolygonZoneAnnotator]): A list of annotators for
drawing zone annotations.
box_annotators (List[sv.BoundingBoxAnnotator]): A list of annotators for
drawing box annotations.
detections (sv.Detections): Detections to be used for annotation.
Returns:
np.ndarray: The annotated frame.
"""
annotated_frame = frame.copy()
for zone, zone_annotator, box_annotator in zip(
zones, zone_annotators, box_annotators
):
detections_in_zone = detections[zone.trigger(detections=detections)]
annotated_frame = zone_annotator.annotate(scene=annotated_frame)
annotated_frame = box_annotator.annotate(
scene=annotated_frame, detections=detections_in_zone
)
return annotated_frame
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Counting people in zones with Inference and Supervision"
)
parser.add_argument(
"--zone_configuration_path",
required=True,
help="Path to the zone configuration JSON file",
type=str,
)
parser.add_argument(
"--model_id",
default="yolov8x-1280",
help="Roboflow model ID",
type=str,
)
parser.add_argument(
"--roboflow_api_key",
default=None,
help="Roboflow API KEY",
type=str,
)
parser.add_argument(
"--source_video_path",
required=True,
help="Path to the source video file",
type=str,
)
parser.add_argument(
"--target_video_path",
default=None,
help="Path to the target video file (output)",
type=str,
)
parser.add_argument(
"--confidence_threshold",
default=0.3,
help="Confidence threshold for the model",
type=float,
)
parser.add_argument(
"--iou_threshold",
default=0.7,
help="IOU threshold for the model",
type=float,
)
args = parser.parse_args()
api_key = args.roboflow_api_key
api_key = os.environ.get("ROBOFLOW_API_KEY", api_key)
if api_key is None:
raise ValueError(
"Roboflow API key is missing. Please provide it as an argument or set the "
"ROBOFLOW_API_KEY environment variable."
)
args.roboflow_api_key = api_key
video_info = sv.VideoInfo.from_video_path(args.source_video_path)
polygons = load_zones_config(args.zone_configuration_path)
zones, zone_annotators, box_annotators = initiate_annotators(
polygons=polygons, resolution_wh=video_info.resolution_wh
)
model = get_roboflow_model(model_id=args.model_id, api_key=args.roboflow_api_key)
frames_generator = sv.get_video_frames_generator(args.source_video_path)
if args.target_video_path is not None:
with sv.VideoSink(args.target_video_path, video_info) as sink:
for frame in tqdm(frames_generator, total=video_info.total_frames):
detections = detect(frame, model, args.confidence_threshold)
annotated_frame = annotate(
frame=frame,
zones=zones,
zone_annotators=zone_annotators,
box_annotators=box_annotators,
detections=detections,
)
sink.write_frame(annotated_frame)
else:
for frame in tqdm(frames_generator, total=video_info.total_frames):
detections = detect(frame, model, args.confidence_threshold)
annotated_frame = annotate(
frame=frame,
zones=zones,
zone_annotators=zone_annotators,
box_annotators=box_annotators,
detections=detections,
)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
@@ -0,0 +1,5 @@
gdown
inference
supervision==0.19.0
tqdm
ultralytics
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# Get the directory where the script is located
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Check if 'data' directory does not exist and then create it
if [[ ! -e $DIR/data ]]; then
mkdir "$DIR/data"
else
echo "'data' directory already exists."
fi
# Download the market-square.mp4 file from Google Drive
gdown -O "$DIR/data/market-square.mp4" "https://drive.google.com/uc?id=1vVrEVMxucHgqGd7vAa501ASojbeGPhIr"
@@ -0,0 +1,206 @@
import argparse
import json
from typing import List, Tuple
import cv2
import numpy as np
from tqdm import tqdm
from ultralytics import YOLO
import supervision as sv
COLORS = sv.ColorPalette.default()
def load_zones_config(file_path: str) -> List[np.ndarray]:
"""
Load polygon zone configurations from a JSON file.
This function reads a JSON file which contains polygon coordinates, and
converts them into a list of NumPy arrays. Each polygon is represented as
a NumPy array of coordinates.
Args:
file_path (str): The path to the JSON configuration file.
Returns:
List[np.ndarray]: A list of polygons, each represented as a NumPy array.
"""
with open(file_path, "r") as file:
data = json.load(file)
return [np.array(polygon, np.int32) for polygon in data["polygons"]]
def initiate_annotators(
polygons: List[np.ndarray], resolution_wh: Tuple[int, int]
) -> Tuple[
List[sv.PolygonZone], List[sv.PolygonZoneAnnotator], List[sv.BoundingBoxAnnotator]
]:
line_thickness = sv.calculate_dynamic_line_thickness(resolution_wh=resolution_wh)
text_scale = sv.calculate_dynamic_text_scale(resolution_wh=resolution_wh)
zones = []
zone_annotators = []
box_annotators = []
for index, polygon in enumerate(polygons):
zone = sv.PolygonZone(polygon=polygon, frame_resolution_wh=resolution_wh)
zone_annotator = sv.PolygonZoneAnnotator(
zone=zone,
color=COLORS.by_idx(index),
thickness=line_thickness,
text_thickness=line_thickness * 2,
text_scale=text_scale * 2,
)
box_annotator = sv.BoundingBoxAnnotator(
color=COLORS.by_idx(index), thickness=line_thickness
)
zones.append(zone)
zone_annotators.append(zone_annotator)
box_annotators.append(box_annotator)
return zones, zone_annotators, box_annotators
def detect(
frame: np.ndarray, model: YOLO, confidence_threshold: float = 0.5
) -> sv.Detections:
"""
Detect objects in a frame using a YOLO model, filtering detections by class ID and
confidence threshold.
Args:
frame (np.ndarray): The frame to process, expected to be a NumPy array.
model (YOLO): The YOLO model used for processing the frame.
confidence_threshold (float, optional): The confidence threshold for filtering
detections. Default is 0.5.
Returns:
sv.Detections: Filtered detections after processing the frame with the YOLO
model.
Note:
This function is specifically tailored for a YOLO model and assumes class ID 0
for filtering.
"""
results = model(frame, imgsz=1280, verbose=False)[0]
detections = sv.Detections.from_ultralytics(results)
filter_by_class = detections.class_id == 0
filter_by_confidence = detections.confidence > confidence_threshold
return detections[filter_by_class & filter_by_confidence]
def annotate(
frame: np.ndarray,
zones: List[sv.PolygonZone],
zone_annotators: List[sv.PolygonZoneAnnotator],
box_annotators: List[sv.BoundingBoxAnnotator],
detections: sv.Detections,
) -> np.ndarray:
"""
Annotate a frame with zone and box annotations based on given detections.
Args:
frame (np.ndarray): The original frame to be annotated.
zones (List[sv.PolygonZone]): A list of polygon zones used for detection.
zone_annotators (List[sv.PolygonZoneAnnotator]): A list of annotators for
drawing zone annotations.
box_annotators (List[sv.BoundingBoxAnnotator]): A list of annotators for
drawing box annotations.
detections (sv.Detections): Detections to be used for annotation.
Returns:
np.ndarray: The annotated frame.
"""
annotated_frame = frame.copy()
for zone, zone_annotator, box_annotator in zip(
zones, zone_annotators, box_annotators
):
detections_in_zone = detections[zone.trigger(detections=detections)]
annotated_frame = zone_annotator.annotate(scene=annotated_frame)
annotated_frame = box_annotator.annotate(
scene=annotated_frame, detections=detections_in_zone
)
return annotated_frame
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Counting people in zones with YOLO and Supervision"
)
parser.add_argument(
"--zone_configuration_path",
required=True,
help="Path to the zone configuration JSON file",
type=str,
)
parser.add_argument(
"--source_weights_path",
default="yolov8x.pt",
help="Path to the source weights file",
type=str,
)
parser.add_argument(
"--source_video_path",
required=True,
help="Path to the source video file",
type=str,
)
parser.add_argument(
"--target_video_path",
default=None,
help="Path to the target video file (output)",
type=str,
)
parser.add_argument(
"--confidence_threshold",
default=0.3,
help="Confidence threshold for the model",
type=float,
)
parser.add_argument(
"--iou_threshold",
default=0.7,
help="IOU threshold for the model",
type=float,
)
args = parser.parse_args()
video_info = sv.VideoInfo.from_video_path(args.source_video_path)
polygons = load_zones_config(args.zone_configuration_path)
zones, zone_annotators, box_annotators = initiate_annotators(
polygons=polygons, resolution_wh=video_info.resolution_wh
)
model = YOLO(args.source_weights_path)
frames_generator = sv.get_video_frames_generator(args.source_video_path)
if args.target_video_path is not None:
with sv.VideoSink(args.target_video_path, video_info) as sink:
for frame in tqdm(frames_generator, total=video_info.total_frames):
detections = detect(frame, model, args.confidence_threshold)
annotated_frame = annotate(
frame=frame,
zones=zones,
zone_annotators=zone_annotators,
box_annotators=box_annotators,
detections=detections,
)
sink.write_frame(annotated_frame)
else:
for frame in tqdm(frames_generator, total=video_info.total_frames):
detections = detect(frame, model, args.confidence_threshold)
annotated_frame = annotate(
frame=frame,
zones=zones,
zone_annotators=zone_annotators,
box_annotators=box_annotators,
detections=detections,
)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
+75
View File
@@ -0,0 +1,75 @@
# heatmap and tracking
## 👋 hello
This script performs heatmap and tracking analysis using YOLOv8, an object-detection method and
ByteTrack, a simple yet effective online multi-object tracking method. It uses the
supervision package for multiple tasks such as drawing heatmap annotations, tracking objects, etc.
## 💻 install
- clone repository and navigate to example directory
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/heatmap_and_track
```
- setup python environment and activate it [optional]
```bash
python3 -m venv venv
source venv/bin/activate
```
- install required dependencies
```bash
pip install -r requirements.txt
```
## 🛠️ script arguments
- `--source_weights_path`: Required. Specifies the path to the weights file for the
YOLO model. This file contains the trained model data necessary for object detection.
- `--source_video_path` (optional): The path to the source video file that will be
analyzed. This is the input video on which crowd analysis will be performed.
If not specified default is `people-walking.mp4` from supervision assets
- `--target_video_path` (optional): The path to save the output.mp4 video with annotations.
- `--confidence_threshold` (optional): Sets the confidence threshold for the YOLO model
to filter detections. Default is `0.3`. This determines how confident the model should
be to recognize an object in the video.
- `--iou_threshold` (optional): Specifies the IOU (Intersection Over Union) threshold
for the model. Default is 0.7. This value is used to manage object detection accuracy,
particularly in distinguishing between different objects.
- `--heatmap_alpha` (optional): Opacity of the overlay mask, between 0 and 1.
- `--radius` (optional): Radius of the heat circle.
- `--track_threshold` (optional): Detection confidence threshold for track activation.
- `--track_seconds` (optional): Number of seconds to buffer when a track is lost.
- `--match_threshold` (optional): Threshold for matching tracks with detections.
## ⚙️ run
```bash
python script.py \
--source_weights_path weight.pt \
--source_video_path input_video.mp4 \
--confidence_threshold 0.3 \
--iou_threshold 0.5 \
--target_video_path output_video.mp4
```
## © license
This demo integrates two main components, each with its own licensing:
- ultralytics: The object detection model used in this demo, YOLOv8, is distributed
under the [AGPL-3.0 license](https://github.com/ultralytics/ultralytics/blob/main/LICENSE).
You can find more details about this license here.
- supervision: The analytics code that powers the zone-based analysis in this demo is
based on the Supervision library, which is licensed under the
[MIT license](https://github.com/roboflow/supervision/blob/develop/LICENSE.md). This
makes the Supervision part of the code fully open source and freely usable in your
projects.
@@ -0,0 +1,2 @@
supervision[assets]==0.19.0
ultralytics
+181
View File
@@ -0,0 +1,181 @@
import argparse
import cv2
from ultralytics import YOLO
import supervision as sv
from supervision.assets import VideoAssets, download_assets
def download_video() -> str:
download_assets(VideoAssets.PEOPLE_WALKING)
return VideoAssets.PEOPLE_WALKING.value
def heatmap_and_track(
source_weights_path: str,
source_video_path: str,
target_video_path: str,
confidence_threshold: float = 0.35,
iou_threshold: float = 0.5,
heatmap_alpha: float = 0.5,
radius: int = 25,
track_threshold: float = 0.35,
track_seconds: int = 5,
match_threshold: float = 0.99,
) -> None:
### instantiate model
model = YOLO(source_weights_path)
### heatmap config
heat_map_annotator = sv.HeatMapAnnotator(
position=sv.Position.BOTTOM_CENTER,
opacity=heatmap_alpha,
radius=radius,
kernel_size=25,
top_hue=0,
low_hue=125,
)
### annotation config
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
### get the video fps
cap = cv2.VideoCapture(source_video_path)
fps = int(cap.get(cv2.CAP_PROP_FPS))
cap.release()
### tracker config
byte_tracker = sv.ByteTrack(
track_thresh=track_threshold,
track_buffer=track_seconds * fps,
match_thresh=match_threshold,
frame_rate=fps,
)
### video config
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
frames_generator = sv.get_video_frames_generator(
source_path=source_video_path, stride=1
)
### Detect, track, annotate, save
with sv.VideoSink(target_path=target_video_path, video_info=video_info) as sink:
for frame in frames_generator:
result = model(
source=frame,
classes=[0], # only person class
conf=confidence_threshold,
iou=iou_threshold,
# show_conf = True,
# save_txt = True,
# save_conf = True,
# save = True,
device=None, # use None = CPU, 0 = single GPU, or [0,1] = dual GPU
)[0]
detections = sv.Detections.from_ultralytics(result) # get detections
detections = byte_tracker.update_with_detections(
detections
) # update tracker
### draw heatmap
annotated_frame = heat_map_annotator.annotate(
scene=frame.copy(), detections=detections
)
### draw other attributes from `detections` object
labels = [
f"#{tracker_id}"
for class_id, tracker_id in zip(
detections.class_id, detections.tracker_id
)
]
label_annotator.annotate(
scene=annotated_frame, detections=detections, labels=labels
)
sink.write_frame(frame=annotated_frame)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Heatmap and Tracking with Supervision"
)
parser.add_argument(
"--source_weights_path",
required=True,
help="Path to the source weights file",
type=str,
)
parser.add_argument(
"--source_video_path",
default=download_video(),
help="Path to the source video file",
type=str,
)
parser.add_argument(
"--target_video_path",
default="output.mp4",
help="Path to the target video file (output)",
type=str,
)
parser.add_argument(
"--confidence_threshold",
default=0.35,
help="Confidence threshold for the model",
type=float,
)
parser.add_argument(
"--iou_threshold",
default=0.5,
help="IOU threshold for the model",
type=float,
)
parser.add_argument(
"--heatmap_alpha",
default=0.5,
help="Opacity of the overlay mask, between 0 and 1",
type=float,
)
parser.add_argument(
"--radius",
default=25,
help="Radius of the heat circle",
type=float,
)
parser.add_argument(
"--track_threshold",
default=0.35,
help="Detection confidence threshold for track activation",
type=float,
)
parser.add_argument(
"--track_seconds",
default=5,
help="Number of seconds to buffer when a track is lost",
type=int,
)
parser.add_argument(
"--match_threshold",
default=0.99,
help="Threshold for matching tracks with detections",
type=float,
)
args = parser.parse_args()
heatmap_and_track(
source_weights_path=args.source_weights_path,
source_video_path=args.source_video_path,
target_video_path=args.target_video_path,
confidence_threshold=args.confidence_threshold,
iou_threshold=args.iou_threshold,
heatmap_alpha=args.heatmap_alpha,
radius=args.radius,
track_threshold=args.track_threshold,
track_seconds=args.track_seconds,
match_threshold=args.match_threshold,
)
+9
View File
@@ -0,0 +1,9 @@
data/
venv*/
*.pt
*.pth
*.mp4
*.mov
*.png
*.jpg
*.jpeg
+117
View File
@@ -0,0 +1,117 @@
# speed estimation
[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-estimate-vehicle-speed-with-computer-vision.ipynb)
[![YouTube](https://badges.aleen42.com/src/youtube.svg)](https://youtu.be/uWP6UjDeZvY)
## 👋 hello
This example performs speed estimation analysis using various object-detection models
and ByteTrack - a simple yet effective online multi-object tracking method. It uses the
supervision package for multiple tasks such as tracking, annotations, etc.
https://github.com/roboflow/supervision/assets/26109316/d50118c1-2ae4-458d-915a-5d860fd36f71
> [!IMPORTANT]
> Adjust the [`SOURCE`](https://github.com/roboflow/supervision/blob/e32b05a636dab2ea1f39299e529c4b22b8baa8da/examples/speed_estimation/ultralytics_example.py#L10)
> and [`TARGET`](https://github.com/roboflow/supervision/blob/e32b05a636dab2ea1f39299e529c4b22b8baa8da/examples/speed_estimation/ultralytics_example.py#L15)
> configuration if you plan to run a speed estimation script on your video file. Those must be adjusted separately for each camera view. You can learn more
> from our YouTube [tutorial](https://youtu.be/uWP6UjDeZvY).
## 💻 install
- clone repository and navigate to example directory
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/speed_estimation
```
- setup python environment and activate it [optional]
```bash
python3.10 -m venv venv
source venv/bin/activate
```
- install required dependencies
```bash
pip install -r requirements.txt
```
- download `vehicles.mp4` file
```bash
python3.10 video_downloader.py
```
## 🛠️ script arguments
- `--roboflow_api_key` (optional): The API key for Roboflow services. If not provided
directly, the script tries to fetch it from the `ROBOFLOW_API_KEY` environment
variable. Follow [this guide](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key)
to acquire your `API KEY`.
- `--model_id` (optional): Designates the Roboflow model ID to be used. The default
value is `"yolov8x-1280"`.
- `--source_weights_path`: Required. Specifies the path to the YOLO model's weights
file, which is essential for the object detection process. This file contains the
data that the model uses to identify objects in the video.
- `--source_video_path`: Required. The path to the source video file that will be
analyzed. This is the input video on which traffic flow analysis will be performed.
- `--target_video_path`: The path to save the output video with
annotations. If not specified, the processed video will be displayed in real-time
without being saved.
- `--confidence_threshold` (optional): Sets the confidence threshold for the YOLO
model to filter detections. Default is `0.3`. This determines how confident the
model should be to recognize an object in the video.
- `--iou_threshold` (optional): Specifies the IOU (Intersection Over Union) threshold
for the model. Default is 0.7. This value is used to manage object detection
accuracy, particularly in distinguishing between different objects.
## ⚙️ run
- yolo-nas
```bash
python yolo_nas_example.py \
--source_video_path data/vehicles.mp4 \
--target_video_path data/vehicles-result.mp4 \
--confidence_threshold 0.3 \
--iou_threshold 0.5
```
- inference
```bash
python inference_example.py \
--roboflow_api_key <ROBOFLOW API KEY> \
--source_video_path data/vehicles.mp4 \
--target_video_path data/vehicles-result.mp4 \
--confidence_threshold 0.3 \
--iou_threshold 0.5
```
- ultralytics
```bash
python ultralytics_example.py \
--source_video_path data/vehicles.mp4 \
--target_video_path data/vehicles-result.mp4 \
--confidence_threshold 0.3 \
--iou_threshold 0.5
```
## © license
This demo integrates two main components, each with its own licensing:
- ultralytics: The object detection model used in this demo, YOLOv8, is distributed
under the [AGPL-3.0 license](https://github.com/ultralytics/ultralytics/blob/main/LICENSE).
You can find more details about this license here.
- supervision: The analytics code that powers the zone-based analysis in this demo is
based on the Supervision library, which is licensed under the
[MIT license](https://github.com/roboflow/supervision/blob/develop/LICENSE.md). This
makes the Supervision part of the code fully open source and freely usable in your
projects.
@@ -0,0 +1,170 @@
import argparse
import os
from collections import defaultdict, deque
import cv2
import numpy as np
from inference.models.utils import get_roboflow_model
import supervision as sv
SOURCE = np.array([[1252, 787], [2298, 803], [5039, 2159], [-550, 2159]])
TARGET_WIDTH = 25
TARGET_HEIGHT = 250
TARGET = np.array(
[
[0, 0],
[TARGET_WIDTH - 1, 0],
[TARGET_WIDTH - 1, TARGET_HEIGHT - 1],
[0, TARGET_HEIGHT - 1],
]
)
class ViewTransformer:
def __init__(self, source: np.ndarray, target: np.ndarray) -> None:
source = source.astype(np.float32)
target = target.astype(np.float32)
self.m = cv2.getPerspectiveTransform(source, target)
def transform_points(self, points: np.ndarray) -> np.ndarray:
if points.size == 0:
return points
reshaped_points = points.reshape(-1, 1, 2).astype(np.float32)
transformed_points = cv2.perspectiveTransform(reshaped_points, self.m)
return transformed_points.reshape(-1, 2)
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Vehicle Speed Estimation using Inference and Supervision"
)
parser.add_argument(
"--model_id",
default="yolov8x-640",
help="Roboflow model ID",
type=str,
)
parser.add_argument(
"--roboflow_api_key",
default=None,
help="Roboflow API KEY",
type=str,
)
parser.add_argument(
"--source_video_path",
required=True,
help="Path to the source video file",
type=str,
)
parser.add_argument(
"--target_video_path",
required=True,
help="Path to the target video file (output)",
type=str,
)
parser.add_argument(
"--confidence_threshold",
default=0.3,
help="Confidence threshold for the model",
type=float,
)
parser.add_argument(
"--iou_threshold", default=0.7, help="IOU threshold for the model", type=float
)
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
api_key = args.roboflow_api_key
api_key = os.environ.get("ROBOFLOW_API_KEY", api_key)
if api_key is None:
raise ValueError(
"Roboflow API key is missing. Please provide it as an argument or set the "
"ROBOFLOW_API_KEY environment variable."
)
args.roboflow_api_key = api_key
video_info = sv.VideoInfo.from_video_path(video_path=args.source_video_path)
model = get_roboflow_model(model_id=args.model_id, api_key=args.roboflow_api_key)
byte_track = sv.ByteTrack(
frame_rate=video_info.fps, track_thresh=args.confidence_threshold
)
thickness = sv.calculate_dynamic_line_thickness(
resolution_wh=video_info.resolution_wh
)
text_scale = sv.calculate_dynamic_text_scale(resolution_wh=video_info.resolution_wh)
bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=thickness)
label_annotator = sv.LabelAnnotator(
text_scale=text_scale,
text_thickness=thickness,
text_position=sv.Position.BOTTOM_CENTER,
)
trace_annotator = sv.TraceAnnotator(
thickness=thickness,
trace_length=video_info.fps * 2,
position=sv.Position.BOTTOM_CENTER,
)
frame_generator = sv.get_video_frames_generator(source_path=args.source_video_path)
polygon_zone = sv.PolygonZone(
polygon=SOURCE, frame_resolution_wh=video_info.resolution_wh
)
view_transformer = ViewTransformer(source=SOURCE, target=TARGET)
coordinates = defaultdict(lambda: deque(maxlen=video_info.fps))
with sv.VideoSink(args.target_video_path, video_info) as sink:
for frame in frame_generator:
results = model.infer(frame)[0]
detections = sv.Detections.from_inference(results)
detections = detections[detections.confidence > args.confidence_threshold]
detections = detections[polygon_zone.trigger(detections)]
detections = detections.with_nms(threshold=args.iou_threshold)
detections = byte_track.update_with_detections(detections=detections)
points = detections.get_anchors_coordinates(
anchor=sv.Position.BOTTOM_CENTER
)
points = view_transformer.transform_points(points=points).astype(int)
for tracker_id, [_, y] in zip(detections.tracker_id, points):
coordinates[tracker_id].append(y)
labels = []
for tracker_id in detections.tracker_id:
if len(coordinates[tracker_id]) < video_info.fps / 2:
labels.append(f"#{tracker_id}")
else:
coordinate_start = coordinates[tracker_id][-1]
coordinate_end = coordinates[tracker_id][0]
distance = abs(coordinate_start - coordinate_end)
time = len(coordinates[tracker_id]) / video_info.fps
speed = distance / time * 3.6
labels.append(f"#{tracker_id} {int(speed)} km/h")
annotated_frame = frame.copy()
annotated_frame = trace_annotator.annotate(
scene=annotated_frame, detections=detections
)
annotated_frame = bounding_box_annotator.annotate(
scene=annotated_frame, detections=detections
)
annotated_frame = label_annotator.annotate(
scene=annotated_frame, detections=detections, labels=labels
)
sink.write_frame(annotated_frame)
cv2.imshow("frame", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
@@ -0,0 +1,6 @@
supervision==0.19.0
tqdm==4.66.1
requests
ultralytics==8.0.237
super-gradients==3.5.0
inference==0.9.8
@@ -0,0 +1,148 @@
import argparse
from collections import defaultdict, deque
import cv2
import numpy as np
from ultralytics import YOLO
import supervision as sv
SOURCE = np.array([[1252, 787], [2298, 803], [5039, 2159], [-550, 2159]])
TARGET_WIDTH = 25
TARGET_HEIGHT = 250
TARGET = np.array(
[
[0, 0],
[TARGET_WIDTH - 1, 0],
[TARGET_WIDTH - 1, TARGET_HEIGHT - 1],
[0, TARGET_HEIGHT - 1],
]
)
class ViewTransformer:
def __init__(self, source: np.ndarray, target: np.ndarray) -> None:
source = source.astype(np.float32)
target = target.astype(np.float32)
self.m = cv2.getPerspectiveTransform(source, target)
def transform_points(self, points: np.ndarray) -> np.ndarray:
if points.size == 0:
return points
reshaped_points = points.reshape(-1, 1, 2).astype(np.float32)
transformed_points = cv2.perspectiveTransform(reshaped_points, self.m)
return transformed_points.reshape(-1, 2)
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Vehicle Speed Estimation using Ultralytics and Supervision"
)
parser.add_argument(
"--source_video_path",
required=True,
help="Path to the source video file",
type=str,
)
parser.add_argument(
"--target_video_path",
required=True,
help="Path to the target video file (output)",
type=str,
)
parser.add_argument(
"--confidence_threshold",
default=0.3,
help="Confidence threshold for the model",
type=float,
)
parser.add_argument(
"--iou_threshold", default=0.7, help="IOU threshold for the model", type=float
)
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
video_info = sv.VideoInfo.from_video_path(video_path=args.source_video_path)
model = YOLO("yolov8x.pt")
byte_track = sv.ByteTrack(
frame_rate=video_info.fps, track_thresh=args.confidence_threshold
)
thickness = sv.calculate_dynamic_line_thickness(
resolution_wh=video_info.resolution_wh
)
text_scale = sv.calculate_dynamic_text_scale(resolution_wh=video_info.resolution_wh)
bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=thickness)
label_annotator = sv.LabelAnnotator(
text_scale=text_scale,
text_thickness=thickness,
text_position=sv.Position.BOTTOM_CENTER,
)
trace_annotator = sv.TraceAnnotator(
thickness=thickness,
trace_length=video_info.fps * 2,
position=sv.Position.BOTTOM_CENTER,
)
frame_generator = sv.get_video_frames_generator(source_path=args.source_video_path)
polygon_zone = sv.PolygonZone(
polygon=SOURCE, frame_resolution_wh=video_info.resolution_wh
)
view_transformer = ViewTransformer(source=SOURCE, target=TARGET)
coordinates = defaultdict(lambda: deque(maxlen=video_info.fps))
with sv.VideoSink(args.target_video_path, video_info) as sink:
for frame in frame_generator:
result = model(frame)[0]
detections = sv.Detections.from_ultralytics(result)
detections = detections[detections.confidence > args.confidence_threshold]
detections = detections[polygon_zone.trigger(detections)]
detections = detections.with_nms(threshold=args.iou_threshold)
detections = byte_track.update_with_detections(detections=detections)
points = detections.get_anchors_coordinates(
anchor=sv.Position.BOTTOM_CENTER
)
points = view_transformer.transform_points(points=points).astype(int)
for tracker_id, [_, y] in zip(detections.tracker_id, points):
coordinates[tracker_id].append(y)
labels = []
for tracker_id in detections.tracker_id:
if len(coordinates[tracker_id]) < video_info.fps / 2:
labels.append(f"#{tracker_id}")
else:
coordinate_start = coordinates[tracker_id][-1]
coordinate_end = coordinates[tracker_id][0]
distance = abs(coordinate_start - coordinate_end)
time = len(coordinates[tracker_id]) / video_info.fps
speed = distance / time * 3.6
labels.append(f"#{tracker_id} {int(speed)} km/h")
annotated_frame = frame.copy()
annotated_frame = trace_annotator.annotate(
scene=annotated_frame, detections=detections
)
annotated_frame = bounding_box_annotator.annotate(
scene=annotated_frame, detections=detections
)
annotated_frame = label_annotator.annotate(
scene=annotated_frame, detections=detections, labels=labels
)
sink.write_frame(annotated_frame)
cv2.imshow("frame", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
@@ -0,0 +1,8 @@
import os
from supervision.assets import VideoAssets, download_assets
if not os.path.exists("data"):
os.makedirs("data")
os.chdir("data")
download_assets(VideoAssets.VEHICLES)
@@ -0,0 +1,148 @@
import argparse
from collections import defaultdict, deque
import cv2
import numpy as np
from super_gradients.common.object_names import Models
from super_gradients.training import models
import supervision as sv
SOURCE = np.array([[1252, 787], [2298, 803], [5039, 2159], [-550, 2159]])
TARGET_WIDTH = 25
TARGET_HEIGHT = 250
TARGET = np.array(
[
[0, 0],
[TARGET_WIDTH - 1, 0],
[TARGET_WIDTH - 1, TARGET_HEIGHT - 1],
[0, TARGET_HEIGHT - 1],
]
)
class ViewTransformer:
def __init__(self, source: np.ndarray, target: np.ndarray) -> None:
source = source.astype(np.float32)
target = target.astype(np.float32)
self.m = cv2.getPerspectiveTransform(source, target)
def transform_points(self, points: np.ndarray) -> np.ndarray:
if points.size == 0:
return points
reshaped_points = points.reshape(-1, 1, 2).astype(np.float32)
transformed_points = cv2.perspectiveTransform(reshaped_points, self.m)
return transformed_points.reshape(-1, 2)
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Vehicle Speed Estimation using YOLO-NAS and Supervision"
)
parser.add_argument(
"--source_video_path",
required=True,
help="Path to the source video file",
type=str,
)
parser.add_argument(
"--target_video_path",
required=True,
help="Path to the target video file (output)",
type=str,
)
parser.add_argument(
"--confidence_threshold",
default=0.3,
help="Confidence threshold for the model",
type=float,
)
parser.add_argument(
"--iou_threshold", default=0.7, help="IOU threshold for the model", type=float
)
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
video_info = sv.VideoInfo.from_video_path(video_path=args.source_video_path)
model = models.get(Models.YOLO_NAS_L, pretrained_weights="coco")
byte_track = sv.ByteTrack(
frame_rate=video_info.fps, track_thresh=args.confidence_threshold
)
thickness = sv.calculate_dynamic_line_thickness(
resolution_wh=video_info.resolution_wh
)
text_scale = sv.calculate_dynamic_text_scale(resolution_wh=video_info.resolution_wh)
bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=thickness)
label_annotator = sv.LabelAnnotator(
text_scale=text_scale,
text_thickness=thickness,
text_position=sv.Position.BOTTOM_CENTER,
)
trace_annotator = sv.TraceAnnotator(
thickness=thickness,
trace_length=video_info.fps * 2,
position=sv.Position.BOTTOM_CENTER,
)
frame_generator = sv.get_video_frames_generator(source_path=args.source_video_path)
polygon_zone = sv.PolygonZone(
polygon=SOURCE, frame_resolution_wh=video_info.resolution_wh
)
view_transformer = ViewTransformer(source=SOURCE, target=TARGET)
coordinates = defaultdict(lambda: deque(maxlen=video_info.fps))
with sv.VideoSink(args.target_video_path, video_info) as sink:
for frame in frame_generator:
result = model.predict(frame)[0]
detections = sv.Detections.from_yolo_nas(result)
detections = detections[polygon_zone.trigger(detections)]
detections = detections.with_nms(threshold=args.iou_threshold)
detections = byte_track.update_with_detections(detections=detections)
points = detections.get_anchors_coordinates(
anchor=sv.Position.BOTTOM_CENTER
)
points = view_transformer.transform_points(points=points).astype(int)
for tracker_id, [_, y] in zip(detections.tracker_id, points):
coordinates[tracker_id].append(y)
labels = []
for tracker_id in detections.tracker_id:
if len(coordinates[tracker_id]) < video_info.fps / 2:
labels.append(f"#{tracker_id}")
else:
coordinate_start = coordinates[tracker_id][-1]
coordinate_end = coordinates[tracker_id][0]
distance = abs(coordinate_start - coordinate_end)
time = len(coordinates[tracker_id]) / video_info.fps
speed = distance / time * 3.6
labels.append(f"#{tracker_id} {int(speed)} km/h")
annotated_frame = frame.copy()
annotated_frame = trace_annotator.annotate(
scene=annotated_frame, detections=detections
)
annotated_frame = bounding_box_annotator.annotate(
scene=annotated_frame, detections=detections
)
annotated_frame = label_annotator.annotate(
scene=annotated_frame, detections=detections, labels=labels
)
sink.write_frame(annotated_frame)
cv2.imshow("frame", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
+9
View File
@@ -0,0 +1,9 @@
data/
venv*/
*.pt
*.pth
*.mp4
*.mov
*.png
*.jpg
*.jpeg
+262
View File
@@ -0,0 +1,262 @@
# time in zone
## 👋 hello
Practical demonstration on leveraging computer vision for analyzing wait times and
monitoring the duration that objects or individuals spend in predefined areas of video
frames. This example project, perfect for retail analytics or traffic management
applications.
https://github.com/roboflow/supervision/assets/26109316/d051cc8a-dd15-41d4-aa36-d38b86334c39
## 💻 install
- clone repository and navigate to example directory
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/time_in_zone
```
- setup python environment and activate it [optional]
```bash
python3 -m venv venv
source venv/bin/activate
```
- install required dependencies
```bash
pip install -r requirements.txt
```
## 🛠 scripts
### `download_from_youtube`
This script allows you to download a video from YouTube.
- `--url`: The full URL of the YouTube video you wish to download.
- `--output_path` (optional): Specifies the directory where the video will be saved.
- `--file_name` (optional): Sets the name of the saved video file.
```bash
python scripts/download_from_youtube.py \
--url "https://www.youtube.com/watch?v=-8zyEwAa50Q" \
--output_path "data/checkout" \
--file_name "video.mp4"
```
```bash
python scripts/download_from_youtube.py \
--url "https://www.youtube.com/watch?v=MNn9qKG2UFI" \
--output_path "data/traffic" \
--file_name "video.mp4"
```
### `stream_from_file`
This script allows you to stream video files from a directory. It's an awesome way to
mock a live video stream for local testing. Video will be streamed in a loop under
`rtsp://localhost:8554/live0.stream` URL. This script requires docker to be installed.
- `--video_directory`: Directory containing video files to stream.
- `--number_of_streams`: Number of video files to stream.
```bash
python scripts/stream_from_file.py \
--video_directory "data/checkout" \
--number_of_streams 1
```
```bash
python scripts/stream_from_file.py \
--video_directory "data/traffic" \
--number_of_streams 1
```
### `draw_zones`
If you want to test zone time in zone analysis on your own video, you can use this
script to design custom zones and save results as a JSON file. The script will open a
window where you can draw polygons on the source image or video file. The polygons will
be saved as a JSON file.
- `--source_path`: Path to the source image or video file for drawing polygons.
- `--zone_configuration_path`: Path where the polygon annotations will be saved as a JSON file.
- `enter` - finish drawing the current polygon.
- `escape` - cancel drawing the current polygon.
- `q` - quit the drawing window.
- `s` - save zone configuration to a JSON file.
```bash
python scripts/draw_zones.py \
--source_path "data/checkout/video.mp4" \
--zone_configuration_path "data/checkout/config.json"
```
```bash
python scripts/draw_zones.py \
--source_path "data/traffic/video.mp4" \
--zone_configuration_path "data/traffic/custom_config.json"
```
https://github.com/roboflow/supervision/assets/26109316/9d514c9e-2a61-418b-ae49-6ac1ad6ae5ac
## 🎬 video & stream processing
### `inference_file_example`
Script to run object detection on a video file using the Roboflow Inference model.
- `--zone_configuration_path`: Path to the zone configuration JSON file.
- `--source_video_path`: Path to the source video file.
- `--model_id`: Roboflow model ID.
- `--classes`: List of class IDs to track. If empty, all classes are tracked.
- `--confidence_threshold`: Confidence level for detections (`0` to `1`). Default is `0.3`.
- `--iou_threshold`: IOU threshold for non-max suppression. Default is `0.7`.
```bash
python inference_file_example.py \
--zone_configuration_path "data/checkout/config.json" \
--source_video_path "data/checkout/video.mp4" \
--model_id "yolov8x-640" \
--classes 0 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
https://github.com/roboflow/supervision/assets/26109316/d051cc8a-dd15-41d4-aa36-d38b86334c39
```bash
python inference_file_example.py \
--zone_configuration_path "data/traffic/config.json" \
--source_video_path "data/traffic/video.mp4" \
--model_id "yolov8x-640" \
--classes 2 5 6 7 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
https://github.com/roboflow/supervision/assets/26109316/5ec896d7-4b39-4426-8979-11e71666878b
### `inference_stream_example`
Script to run object detection on a video stream using the Roboflow Inference model.
- `--zone_configuration_path`: Path to the zone configuration JSON file.
- `--rtsp_url`: Complete RTSP URL for the video stream.
- `--model_id`: Roboflow model ID.
- `--classes`: List of class IDs to track. If empty, all classes are tracked.
- `--confidence_threshold`: Confidence level for detections (`0` to `1`). Default is `0.3`.
- `--iou_threshold`: IOU threshold for non-max suppression. Default is `0.7`.
```bash
python inference_file_example.py \
--zone_configuration_path "data/checkout/config.json" \
--rtsp_url "rtsp://localhost:8554/live0.stream" \
--model_id "yolov8x-640" \
--classes 0 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
```bash
python inference_file_example.py \
--zone_configuration_path "data/traffic/config.json" \
--rtsp_url "rtsp://localhost:8554/live0.stream" \
--model_id "yolov8x-640" \
--classes 2 5 6 7 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
<details>
<summary>👉 show ultralytics examples</summary>
### `ultralytics_file_example`
Script to run object detection on a video file using the Ultralytics YOLOv8 model.
- `--zone_configuration_path`: Path to the zone configuration JSON file.
- `--source_video_path`: Path to the source video file.
- `--weights`: Path to the model weights file. Default is `'yolov8s.pt'`.
- `--device`: Computation device (`'cpu'`, `'mps'` or `'cuda'`). Default is `'cpu'`.
- `--classes`: List of class IDs to track. If empty, all classes are tracked.
- `--confidence_threshold`: Confidence level for detections (`0` to `1`). Default is `0.3`.
- `--iou_threshold`: IOU threshold for non-max suppression. Default is `0.7`.
```bash
python inference_file_example.py \
--zone_configuration_path "data/checkout/config.json" \
--source_video_path "data/checkout/video.mp4" \
--weights "yolov8x.pt" \
--device "cpu" \
--classes 0 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
```bash
python inference_file_example.py \
--zone_configuration_path "data/traffic/config.json" \
--source_video_path "data/traffic/video.mp4" \
--weights "yolov8x.pt" \
--device "cpu" \
--classes 2 5 6 7 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
### `ultralytics_stream_example`
Script to run object detection on a video stream using the Ultralytics YOLOv8 model.
- `--zone_configuration_path`: Path to the zone configuration JSON file.
- `--rtsp_url`: Complete RTSP URL for the video stream.
- `--weights`: Path to the model weights file. Default is `'yolov8s.pt'`.
- `--device`: Computation device (`'cpu'`, `'mps'` or `'cuda'`). Default is `'cpu'`.
- `--classes`: List of class IDs to track. If empty, all classes are tracked.
- `--confidence_threshold`: Confidence level for detections (`0` to `1`). Default is `0.3`.
- `--iou_threshold`: IOU threshold for non-max suppression. Default is `0.7`.
```bash
python inference_file_example.py \
--zone_configuration_path "data/checkout/config.json" \
--rtsp_url "rtsp://localhost:8554/live0.stream" \
--weights "yolov8x.pt" \
--device "cpu" \
--classes 0 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
```bash
python inference_file_example.py \
--zone_configuration_path "data/traffic/config.json" \
--rtsp_url "rtsp://localhost:8554/live0.stream" \
--weights "yolov8x.pt" \
--device "cpu" \
--classes 2 5 6 7 \
--confidence_threshold 0.3 \
--iou_threshold 0.7
```
</details>
## © license
This demo integrates two main components, each with its own licensing:
- ultralytics: The object detection model used in this demo, YOLOv8, is distributed
under the [AGPL-3.0 license](https://github.com/ultralytics/ultralytics/blob/main/LICENSE).
You can find more details about this license here.
- supervision: The analytics code that powers the zone-based analysis in this demo is
based on the Supervision library, which is licensed under the
[MIT license](https://github.com/roboflow/supervision/blob/develop/LICENSE.md). This
makes the Supervision part of the code fully open source and freely usable in your
projects.
@@ -0,0 +1,132 @@
import argparse
from typing import List
import cv2
import numpy as np
from inference import get_model
from utils.general import find_in_list, load_zones_config
from utils.timers import FPSBasedTimer
import supervision as sv
COLORS = sv.ColorPalette.from_hex(["#E6194B", "#3CB44B", "#FFE119", "#3C76D1"])
COLOR_ANNOTATOR = sv.ColorAnnotator(color=COLORS)
LABEL_ANNOTATOR = sv.LabelAnnotator(
color=COLORS, text_color=sv.Color.from_hex("#000000")
)
def main(
source_video_path: str,
zone_configuration_path: str,
model_id: str,
confidence: float,
iou: float,
classes: List[int],
) -> None:
model = get_model(model_id=model_id)
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
frames_generator = sv.get_video_frames_generator(source_video_path)
frame = next(frames_generator)
resolution_wh = frame.shape[1], frame.shape[0]
polygons = load_zones_config(file_path=zone_configuration_path)
zones = [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=resolution_wh,
triggering_anchors=(sv.Position.CENTER,),
)
for polygon in polygons
]
timers = [FPSBasedTimer(video_info.fps) for _ in zones]
for frame in frames_generator:
results = model.infer(frame, confidence=confidence, iou_threshold=iou)[0]
detections = sv.Detections.from_inference(results)
detections = detections[find_in_list(detections.class_id, classes)]
detections = tracker.update_with_detections(detections)
annotated_frame = frame.copy()
for idx, zone in enumerate(zones):
annotated_frame = sv.draw_polygon(
scene=annotated_frame, polygon=zone.polygon, color=COLORS.by_idx(idx)
)
detections_in_zone = detections[zone.trigger(detections)]
time_in_zone = timers[idx].tick(detections_in_zone)
custom_color_lookup = np.full(detections_in_zone.class_id.shape, idx)
annotated_frame = COLOR_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
custom_color_lookup=custom_color_lookup,
)
labels = [
f"#{tracker_id} {int(time // 60):02d}:{int(time % 60):02d}"
for tracker_id, time in zip(detections_in_zone.tracker_id, time_in_zone)
]
annotated_frame = LABEL_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
labels=labels,
custom_color_lookup=custom_color_lookup,
)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculating detections dwell time in zones, using video file."
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path to the zone configuration JSON file.",
)
parser.add_argument(
"--source_video_path",
type=str,
required=True,
help="Path to the source video file.",
)
parser.add_argument(
"--model_id", type=str, default="yolov8s-640", help="Roboflow model ID."
)
parser.add_argument(
"--confidence_threshold",
type=float,
default=0.3,
help="Confidence level for detections (0 to 1). Default is 0.3.",
)
parser.add_argument(
"--iou_threshold",
default=0.7,
type=float,
help="IOU threshold for non-max suppression. Default is 0.7.",
)
parser.add_argument(
"--classes",
nargs="*",
type=int,
default=[],
help="List of class IDs to track. If empty, all classes are tracked.",
)
args = parser.parse_args()
main(
source_video_path=args.source_video_path,
zone_configuration_path=args.zone_configuration_path,
model_id=args.model_id,
confidence=args.confidence_threshold,
iou=args.iou_threshold,
classes=args.classes,
)
@@ -0,0 +1,142 @@
import argparse
from typing import List
import cv2
import numpy as np
from inference import get_model
from utils.general import find_in_list, get_stream_frames_generator, load_zones_config
from utils.timers import ClockBasedTimer
import supervision as sv
COLORS = sv.ColorPalette.from_hex(["#E6194B", "#3CB44B", "#FFE119", "#3C76D1"])
COLOR_ANNOTATOR = sv.ColorAnnotator(color=COLORS)
LABEL_ANNOTATOR = sv.LabelAnnotator(
color=COLORS, text_color=sv.Color.from_hex("#000000")
)
def main(
rtsp_url: str,
zone_configuration_path: str,
model_id: str,
confidence: float,
iou: float,
classes: List[int],
) -> None:
model = get_model(model_id=model_id)
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
frames_generator = get_stream_frames_generator(rtsp_url=rtsp_url)
fps_monitor = sv.FPSMonitor()
frame = next(frames_generator)
resolution_wh = frame.shape[1], frame.shape[0]
polygons = load_zones_config(file_path=zone_configuration_path)
zones = [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=resolution_wh,
triggering_anchors=(sv.Position.CENTER,),
)
for polygon in polygons
]
timers = [ClockBasedTimer() for _ in zones]
for frame in frames_generator:
fps_monitor.tick()
fps = fps_monitor.fps
results = model.infer(frame, confidence=confidence, iou_threshold=iou)[0]
detections = sv.Detections.from_inference(results)
detections = detections[find_in_list(detections.class_id, classes)]
detections = tracker.update_with_detections(detections)
annotated_frame = frame.copy()
annotated_frame = sv.draw_text(
scene=annotated_frame,
text=f"{fps:.1f}",
text_anchor=sv.Point(40, 30),
background_color=sv.Color.from_hex("#A351FB"),
text_color=sv.Color.from_hex("#000000"),
)
for idx, zone in enumerate(zones):
annotated_frame = sv.draw_polygon(
scene=annotated_frame, polygon=zone.polygon, color=COLORS.by_idx(idx)
)
detections_in_zone = detections[zone.trigger(detections)]
time_in_zone = timers[idx].tick(detections_in_zone)
custom_color_lookup = np.full(detections_in_zone.class_id.shape, idx)
annotated_frame = COLOR_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
custom_color_lookup=custom_color_lookup,
)
labels = [
f"#{tracker_id} {int(time // 60):02d}:{int(time % 60):02d}"
for tracker_id, time in zip(detections_in_zone.tracker_id, time_in_zone)
]
annotated_frame = LABEL_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
labels=labels,
custom_color_lookup=custom_color_lookup,
)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculating detections dwell time in zones, using RTSP stream."
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path to the zone configuration JSON file.",
)
parser.add_argument(
"--rtsp_url",
type=str,
required=True,
help="Complete RTSP URL for the video stream.",
)
parser.add_argument(
"--model_id", type=str, default="yolov8s-640", help="Roboflow model ID."
)
parser.add_argument(
"--confidence_threshold",
type=float,
default=0.3,
help="Confidence level for detections (0 to 1). Default is 0.3.",
)
parser.add_argument(
"--iou_threshold",
default=0.7,
type=float,
help="IOU threshold for non-max suppression. Default is 0.7.",
)
parser.add_argument(
"--classes",
nargs="*",
type=int,
default=[],
help="List of class IDs to track. If empty, all classes are tracked.",
)
args = parser.parse_args()
main(
rtsp_url=args.rtsp_url,
zone_configuration_path=args.zone_configuration_path,
model_id=args.model_id,
confidence=args.confidence_threshold,
iou=args.iou_threshold,
classes=args.classes,
)
@@ -0,0 +1,158 @@
import argparse
from typing import List
import cv2
import numpy as np
from inference import InferencePipeline
from inference.core.interfaces.camera.entities import VideoFrame
from utils.general import find_in_list, load_zones_config
from utils.timers import ClockBasedTimer
import supervision as sv
COLORS = sv.ColorPalette.from_hex(["#E6194B", "#3CB44B", "#FFE119", "#3C76D1"])
COLOR_ANNOTATOR = sv.ColorAnnotator(color=COLORS)
LABEL_ANNOTATOR = sv.LabelAnnotator(
color=COLORS, text_color=sv.Color.from_hex("#000000")
)
class CustomSink:
def __init__(self, zone_configuration_path: str, classes: List[int]):
self.classes = classes
self.tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
self.fps_monitor = sv.FPSMonitor()
self.polygons = load_zones_config(file_path=zone_configuration_path)
self.timers = [ClockBasedTimer() for _ in self.polygons]
self.zones = None
def on_prediction(self, result: dict, frame: VideoFrame) -> None:
if self.zones is None:
resolution_wh = frame.image.shape[1], frame.image.shape[0]
self.zones = [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=resolution_wh,
triggering_anchors=(sv.Position.CENTER,),
)
for polygon in self.polygons
]
self.fps_monitor.tick()
fps = self.fps_monitor.fps
detections = sv.Detections.from_inference(result)
detections = detections[find_in_list(detections.class_id, self.classes)]
detections = self.tracker.update_with_detections(detections)
annotated_frame = frame.image.copy()
annotated_frame = sv.draw_text(
scene=annotated_frame,
text=f"{fps:.1f}",
text_anchor=sv.Point(40, 30),
background_color=sv.Color.from_hex("#A351FB"),
text_color=sv.Color.from_hex("#000000"),
)
for idx, zone in enumerate(self.zones):
annotated_frame = sv.draw_polygon(
scene=annotated_frame, polygon=zone.polygon, color=COLORS.by_idx(idx)
)
detections_in_zone = detections[zone.trigger(detections)]
time_in_zone = self.timers[idx].tick(detections_in_zone)
custom_color_lookup = np.full(detections_in_zone.class_id.shape, idx)
annotated_frame = COLOR_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
custom_color_lookup=custom_color_lookup,
)
labels = [
f"#{tracker_id} {int(time // 60):02d}:{int(time % 60):02d}"
for tracker_id, time in zip(detections_in_zone.tracker_id, time_in_zone)
]
annotated_frame = LABEL_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
labels=labels,
custom_color_lookup=custom_color_lookup,
)
cv2.imshow("Processed Video", annotated_frame)
cv2.waitKey(1)
def main(
rtsp_url: str,
zone_configuration_path: str,
model_id: str,
confidence: float,
iou: float,
classes: List[int],
) -> None:
sink = CustomSink(zone_configuration_path=zone_configuration_path, classes=classes)
pipeline = InferencePipeline.init(
model_id=model_id,
video_reference=rtsp_url,
on_prediction=sink.on_prediction,
confidence=confidence,
iou_threshold=iou,
)
pipeline.start()
try:
pipeline.join()
except KeyboardInterrupt:
pipeline.terminate()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculating detections dwell time in zones, using RTSP stream."
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path to the zone configuration JSON file.",
)
parser.add_argument(
"--rtsp_url",
type=str,
required=True,
help="Complete RTSP URL for the video stream.",
)
parser.add_argument(
"--model_id", type=str, default="yolov8s-640", help="Roboflow model ID."
)
parser.add_argument(
"--confidence_threshold",
type=float,
default=0.3,
help="Confidence level for detections (0 to 1). Default is 0.3.",
)
parser.add_argument(
"--iou_threshold",
default=0.7,
type=float,
help="IOU threshold for non-max suppression. Default is 0.7.",
)
parser.add_argument(
"--classes",
nargs="*",
type=int,
default=[],
help="List of class IDs to track. If empty, all classes are tracked.",
)
args = parser.parse_args()
main(
rtsp_url=args.rtsp_url,
zone_configuration_path=args.zone_configuration_path,
model_id=args.model_id,
confidence=args.confidence_threshold,
iou=args.iou_threshold,
classes=args.classes,
)
+5
View File
@@ -0,0 +1,5 @@
opencv-python
supervision
ultralytics
inference
pytube
@@ -0,0 +1,46 @@
import argparse
import os
from typing import Optional
from pytube import YouTube
def main(url: str, output_path: Optional[str], file_name: Optional[str]) -> None:
yt = YouTube(url)
stream = yt.streams.get_highest_resolution()
if not os.path.exists(output_path):
os.makedirs(output_path)
stream.download(output_path=output_path, filename=file_name)
final_name = file_name if file_name else yt.title
final_path = output_path if output_path else "current directory"
print(f"Download completed! Video saved as '{final_name}' in '{final_path}'.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Download a specific YouTube video by providing its URL."
)
parser.add_argument(
"--url",
type=str,
required=True,
help="The full URL of the YouTube video you wish to download.",
)
parser.add_argument(
"--output_path",
type=str,
default="data/source",
required=False,
help="Optional. Specifies the directory where the video will be saved.",
)
parser.add_argument(
"--file_name",
type=str,
default="video.mp4",
required=False,
help="Optional. Sets the name of the saved video file.",
)
args = parser.parse_args()
main(url=args.url, output_path=args.output_path, file_name=args.file_name)
+176
View File
@@ -0,0 +1,176 @@
import argparse
import json
import os
from typing import Any, Optional, Tuple
import cv2
import numpy as np
import supervision as sv
KEY_ENTER = 13
KEY_NEWLINE = 10
KEY_ESCAPE = 27
KEY_QUIT = ord("q")
KEY_SAVE = ord("s")
THICKNESS = 2
COLORS = sv.ColorPalette.DEFAULT
WINDOW_NAME = "Draw Zones"
POLYGONS = [[]]
current_mouse_position: Optional[Tuple[int, int]] = None
def resolve_source(source_path: str) -> Optional[np.ndarray]:
if not os.path.exists(source_path):
return None
image = cv2.imread(source_path)
if image is not None:
return image
frame_generator = sv.get_video_frames_generator(source_path=source_path)
frame = next(frame_generator)
return frame
def mouse_event(event: int, x: int, y: int, flags: int, param: Any) -> None:
global current_mouse_position
if event == cv2.EVENT_MOUSEMOVE:
current_mouse_position = (x, y)
elif event == cv2.EVENT_LBUTTONDOWN:
POLYGONS[-1].append((x, y))
def redraw(image: np.ndarray, original_image: np.ndarray) -> None:
global POLYGONS, current_mouse_position
image[:] = original_image.copy()
for idx, polygon in enumerate(POLYGONS):
color = (
COLORS.by_idx(idx).as_bgr()
if idx < len(POLYGONS) - 1
else sv.Color.WHITE.as_bgr()
)
if len(polygon) > 1:
for i in range(1, len(polygon)):
cv2.line(
img=image,
pt1=polygon[i - 1],
pt2=polygon[i],
color=color,
thickness=THICKNESS,
)
if idx < len(POLYGONS) - 1:
cv2.line(
img=image,
pt1=polygon[-1],
pt2=polygon[0],
color=color,
thickness=THICKNESS,
)
if idx == len(POLYGONS) - 1 and current_mouse_position is not None and polygon:
cv2.line(
img=image,
pt1=polygon[-1],
pt2=current_mouse_position,
color=color,
thickness=THICKNESS,
)
cv2.imshow(WINDOW_NAME, image)
def close_and_finalize_polygon(image: np.ndarray, original_image: np.ndarray) -> None:
if len(POLYGONS[-1]) > 2:
cv2.line(
img=image,
pt1=POLYGONS[-1][-1],
pt2=POLYGONS[-1][0],
color=COLORS.by_idx(0).as_bgr(),
thickness=THICKNESS,
)
POLYGONS.append([])
image[:] = original_image.copy()
redraw_polygons(image)
cv2.imshow(WINDOW_NAME, image)
def redraw_polygons(image: np.ndarray) -> None:
for idx, polygon in enumerate(POLYGONS[:-1]):
if len(polygon) > 1:
color = COLORS.by_idx(idx).as_bgr()
for i in range(len(polygon) - 1):
cv2.line(
img=image,
pt1=polygon[i],
pt2=polygon[i + 1],
color=color,
thickness=THICKNESS,
)
cv2.line(
img=image,
pt1=polygon[-1],
pt2=polygon[0],
color=color,
thickness=THICKNESS,
)
def save_polygons_to_json(polygons, target_path):
data_to_save = polygons if polygons[-1] else polygons[:-1]
with open(target_path, "w") as f:
json.dump(data_to_save, f)
def main(source_path: str, zone_configuration_path: str) -> None:
global current_mouse_position
original_image = resolve_source(source_path=source_path)
if original_image is None:
print("Failed to load source image.")
return
image = original_image.copy()
cv2.imshow(WINDOW_NAME, image)
cv2.setMouseCallback(WINDOW_NAME, mouse_event, image)
while True:
key = cv2.waitKey(1) & 0xFF
if key == KEY_ENTER or key == KEY_NEWLINE:
close_and_finalize_polygon(image, original_image)
elif key == KEY_ESCAPE:
POLYGONS[-1] = []
current_mouse_position = None
elif key == KEY_SAVE:
save_polygons_to_json(POLYGONS, zone_configuration_path)
print(f"Polygons saved to {zone_configuration_path}")
break
redraw(image, original_image)
if key == KEY_QUIT:
break
cv2.destroyAllWindows()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Interactively draw polygons on images or video frames and save "
"the annotations."
)
parser.add_argument(
"--source_path",
type=str,
required=True,
help="Path to the source image or video file for drawing polygons.",
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path where the polygon annotations will be saved as a JSON file.",
)
arguments = parser.parse_args()
main(
source_path=arguments.source_path,
zone_configuration_path=arguments.zone_configuration_path,
)
@@ -0,0 +1,104 @@
import argparse
import os
import subprocess
import tempfile
from glob import glob
from threading import Thread
import yaml
SERVER_CONFIG = {"protocols": ["tcp"], "paths": {"all": {"source": "publisher"}}}
BASE_STREAM_URL = "rtsp://localhost:8554/live"
def main(video_directory: str, number_of_streams: int) -> None:
video_files = find_video_files_in_directory(video_directory, number_of_streams)
try:
with tempfile.TemporaryDirectory() as temporary_directory:
config_file_path = create_server_config_file(temporary_directory)
run_rtsp_server(config_path=config_file_path)
stream_videos(video_files)
finally:
stop_rtsp_server()
def find_video_files_in_directory(directory: str, limit: int) -> list:
video_formats = ["*.mp4", "*.webm"]
video_paths = []
for video_format in video_formats:
video_paths.extend(glob(os.path.join(directory, video_format)))
return video_paths[:limit]
def create_server_config_file(directory: str) -> str:
config_path = os.path.join(directory, "rtsp-simple-server.yml")
with open(config_path, "w") as config_file:
yaml.dump(SERVER_CONFIG, config_file)
return config_path
def run_rtsp_server(config_path: str) -> None:
command = (
"docker run --rm --name rtsp_server -d -v "
f"{config_path}:/rtsp-simple-server.yml -p 8554:8554 "
"aler9/rtsp-simple-server:v1.3.0"
)
if run_command(command.split()) != 0:
raise RuntimeError("Could not start the RTSP server!")
def stop_rtsp_server() -> None:
run_command("docker kill rtsp_server".split())
def stream_videos(video_files: list) -> None:
threads = []
for index, video_file in enumerate(video_files):
stream_url = f"{BASE_STREAM_URL}{index}.stream"
print(f"Streaming {video_file} under {stream_url}")
thread = stream_video_to_url(video_file, stream_url)
threads.append(thread)
for thread in threads:
thread.join()
def stream_video_to_url(video_path: str, stream_url: str) -> Thread:
command = (
f"ffmpeg -re -stream_loop -1 -i {video_path} "
f"-f rtsp -rtsp_transport tcp {stream_url}"
)
return run_command_in_thread(command.split())
def run_command_in_thread(command: list) -> Thread:
thread = Thread(target=run_command, args=(command,))
thread.start()
return thread
def run_command(command: list) -> int:
process = subprocess.run(command)
return process.returncode
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Script to stream videos using RTSP protocol."
)
parser.add_argument(
"--video_directory",
type=str,
required=True,
help="Directory containing video files to stream.",
)
parser.add_argument(
"--number_of_streams",
type=int,
default=6,
help="Number of video files to stream.",
)
arguments = parser.parse_args()
main(
video_directory=arguments.video_directory,
number_of_streams=arguments.number_of_streams,
)
@@ -0,0 +1,144 @@
import argparse
from typing import List
import cv2
import numpy as np
from ultralytics import YOLO
from utils.general import find_in_list, load_zones_config
from utils.timers import FPSBasedTimer
import supervision as sv
COLORS = sv.ColorPalette.from_hex(["#E6194B", "#3CB44B", "#FFE119", "#3C76D1"])
COLOR_ANNOTATOR = sv.ColorAnnotator(color=COLORS)
LABEL_ANNOTATOR = sv.LabelAnnotator(
color=COLORS, text_color=sv.Color.from_hex("#000000")
)
def main(
source_video_path: str,
zone_configuration_path: str,
weights: str,
device: str,
confidence: float,
iou: float,
classes: List[int],
) -> None:
model = YOLO(weights)
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
frames_generator = sv.get_video_frames_generator(source_video_path)
frame = next(frames_generator)
resolution_wh = frame.shape[1], frame.shape[0]
polygons = load_zones_config(file_path=zone_configuration_path)
zones = [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=resolution_wh,
triggering_anchors=(sv.Position.CENTER,),
)
for polygon in polygons
]
timers = [FPSBasedTimer(video_info.fps) for _ in zones]
for frame in frames_generator:
results = model(frame, verbose=False, device=device, conf=confidence)[0]
detections = sv.Detections.from_ultralytics(results)
detections = detections[find_in_list(detections.class_id, classes)]
detections = detections.with_nms(threshold=iou)
detections = tracker.update_with_detections(detections)
annotated_frame = frame.copy()
for idx, zone in enumerate(zones):
annotated_frame = sv.draw_polygon(
scene=annotated_frame, polygon=zone.polygon, color=COLORS.by_idx(idx)
)
detections_in_zone = detections[zone.trigger(detections)]
time_in_zone = timers[idx].tick(detections_in_zone)
custom_color_lookup = np.full(detections_in_zone.class_id.shape, idx)
annotated_frame = COLOR_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
custom_color_lookup=custom_color_lookup,
)
labels = [
f"#{tracker_id} {int(time // 60):02d}:{int(time % 60):02d}"
for tracker_id, time in zip(detections_in_zone.tracker_id, time_in_zone)
]
annotated_frame = LABEL_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
labels=labels,
custom_color_lookup=custom_color_lookup,
)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculating detections dwell time in zones, using video file."
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path to the zone configuration JSON file.",
)
parser.add_argument(
"--source_video_path",
type=str,
required=True,
help="Path to the source video file.",
)
parser.add_argument(
"--weights",
type=str,
default="yolov8s.pt",
help="Path to the model weights file. Default is 'yolov8s.pt'.",
)
parser.add_argument(
"--device",
type=str,
default="cpu",
help="Computation device ('cpu', 'mps' or 'cuda'). Default is 'cpu'.",
)
parser.add_argument(
"--confidence_threshold",
type=float,
default=0.3,
help="Confidence level for detections (0 to 1). Default is 0.3.",
)
parser.add_argument(
"--iou_threshold",
default=0.7,
type=float,
help="IOU threshold for non-max suppression. Default is 0.7.",
)
parser.add_argument(
"--classes",
nargs="*",
type=int,
default=[],
help="List of class IDs to track. If empty, all classes are tracked.",
)
args = parser.parse_args()
main(
source_video_path=args.source_video_path,
zone_configuration_path=args.zone_configuration_path,
weights=args.weights,
device=args.device,
confidence=args.confidence_threshold,
iou=args.iou_threshold,
classes=args.classes,
)
@@ -0,0 +1,154 @@
import argparse
from typing import List
import cv2
import numpy as np
from ultralytics import YOLO
from utils.general import find_in_list, get_stream_frames_generator, load_zones_config
from utils.timers import ClockBasedTimer
import supervision as sv
COLORS = sv.ColorPalette.from_hex(["#E6194B", "#3CB44B", "#FFE119", "#3C76D1"])
COLOR_ANNOTATOR = sv.ColorAnnotator(color=COLORS)
LABEL_ANNOTATOR = sv.LabelAnnotator(
color=COLORS, text_color=sv.Color.from_hex("#000000")
)
def main(
rtsp_url: str,
zone_configuration_path: str,
weights: str,
device: str,
confidence: float,
iou: float,
classes: List[int],
) -> None:
model = YOLO(weights)
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
frames_generator = get_stream_frames_generator(rtsp_url=rtsp_url)
fps_monitor = sv.FPSMonitor()
frame = next(frames_generator)
resolution_wh = frame.shape[1], frame.shape[0]
polygons = load_zones_config(file_path=zone_configuration_path)
zones = [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=resolution_wh,
triggering_anchors=(sv.Position.CENTER,),
)
for polygon in polygons
]
timers = [ClockBasedTimer() for _ in zones]
for frame in frames_generator:
fps_monitor.tick()
fps = fps_monitor.fps
results = model(frame, verbose=False, device=device, conf=confidence)[0]
detections = sv.Detections.from_ultralytics(results)
detections = detections[find_in_list(detections.class_id, classes)]
detections = detections.with_nms(threshold=iou)
detections = tracker.update_with_detections(detections)
annotated_frame = frame.copy()
annotated_frame = sv.draw_text(
scene=annotated_frame,
text=f"{fps:.1f}",
text_anchor=sv.Point(40, 30),
background_color=sv.Color.from_hex("#A351FB"),
text_color=sv.Color.from_hex("#000000"),
)
for idx, zone in enumerate(zones):
annotated_frame = sv.draw_polygon(
scene=annotated_frame, polygon=zone.polygon, color=COLORS.by_idx(idx)
)
detections_in_zone = detections[zone.trigger(detections)]
time_in_zone = timers[idx].tick(detections_in_zone)
custom_color_lookup = np.full(detections_in_zone.class_id.shape, idx)
annotated_frame = COLOR_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
custom_color_lookup=custom_color_lookup,
)
labels = [
f"#{tracker_id} {int(time // 60):02d}:{int(time % 60):02d}"
for tracker_id, time in zip(detections_in_zone.tracker_id, time_in_zone)
]
annotated_frame = LABEL_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
labels=labels,
custom_color_lookup=custom_color_lookup,
)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculating detections dwell time in zones, using RTSP stream."
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path to the zone configuration JSON file.",
)
parser.add_argument(
"--rtsp_url",
type=str,
required=True,
help="Complete RTSP URL for the video stream.",
)
parser.add_argument(
"--weights",
type=str,
default="yolov8s.pt",
help="Path to the model weights file. Default is 'yolov8s.pt'.",
)
parser.add_argument(
"--device",
type=str,
default="cpu",
help="Computation device ('cpu', 'mps' or 'cuda'). Default is 'cpu'.",
)
parser.add_argument(
"--confidence_threshold",
type=float,
default=0.3,
help="Confidence level for detections (0 to 1). Default is 0.3.",
)
parser.add_argument(
"--iou_threshold",
default=0.7,
type=float,
help="IOU threshold for non-max suppression. Default is 0.7.",
)
parser.add_argument(
"--classes",
nargs="*",
type=int,
default=[],
help="List of class IDs to track. If empty, all classes are tracked.",
)
args = parser.parse_args()
main(
rtsp_url=args.rtsp_url,
zone_configuration_path=args.zone_configuration_path,
weights=args.weights,
device=args.device,
confidence=args.confidence_threshold,
iou=args.iou_threshold,
classes=args.classes,
)
@@ -0,0 +1,173 @@
import argparse
from typing import List
import cv2
import numpy as np
from inference import InferencePipeline
from inference.core.interfaces.camera.entities import VideoFrame
from ultralytics import YOLO
from utils.general import find_in_list, load_zones_config
from utils.timers import ClockBasedTimer
import supervision as sv
COLORS = sv.ColorPalette.from_hex(["#E6194B", "#3CB44B", "#FFE119", "#3C76D1"])
COLOR_ANNOTATOR = sv.ColorAnnotator(color=COLORS)
LABEL_ANNOTATOR = sv.LabelAnnotator(
color=COLORS, text_color=sv.Color.from_hex("#000000")
)
class CustomSink:
def __init__(self, zone_configuration_path: str, classes: List[int]):
self.classes = classes
self.tracker = sv.ByteTrack(minimum_matching_threshold=0.8)
self.fps_monitor = sv.FPSMonitor()
self.polygons = load_zones_config(file_path=zone_configuration_path)
self.timers = [ClockBasedTimer() for _ in self.polygons]
self.zones = None
def on_prediction(self, detections: sv.Detections, frame: VideoFrame) -> None:
if self.zones is None:
resolution_wh = frame.image.shape[1], frame.image.shape[0]
self.zones = [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=resolution_wh,
triggering_anchors=(sv.Position.CENTER,),
)
for polygon in self.polygons
]
self.fps_monitor.tick()
fps = self.fps_monitor.fps
detections = detections[find_in_list(detections.class_id, self.classes)]
detections = self.tracker.update_with_detections(detections)
annotated_frame = frame.image.copy()
annotated_frame = sv.draw_text(
scene=annotated_frame,
text=f"{fps:.1f}",
text_anchor=sv.Point(40, 30),
background_color=sv.Color.from_hex("#A351FB"),
text_color=sv.Color.from_hex("#000000"),
)
for idx, zone in enumerate(self.zones):
annotated_frame = sv.draw_polygon(
scene=annotated_frame, polygon=zone.polygon, color=COLORS.by_idx(idx)
)
detections_in_zone = detections[zone.trigger(detections)]
time_in_zone = self.timers[idx].tick(detections_in_zone)
custom_color_lookup = np.full(detections_in_zone.class_id.shape, idx)
annotated_frame = COLOR_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
custom_color_lookup=custom_color_lookup,
)
labels = [
f"#{tracker_id} {int(time // 60):02d}:{int(time % 60):02d}"
for tracker_id, time in zip(detections_in_zone.tracker_id, time_in_zone)
]
annotated_frame = LABEL_ANNOTATOR.annotate(
scene=annotated_frame,
detections=detections_in_zone,
labels=labels,
custom_color_lookup=custom_color_lookup,
)
cv2.imshow("Processed Video", annotated_frame)
cv2.waitKey(1)
def main(
rtsp_url: str,
zone_configuration_path: str,
weights: str,
device: str,
confidence: float,
iou: float,
classes: List[int],
) -> None:
model = YOLO(weights)
def inference_callback(frame: VideoFrame) -> sv.Detections:
results = model(frame.image, verbose=False, conf=confidence, device=device)[0]
return sv.Detections.from_ultralytics(results).with_nms(threshold=iou)
sink = CustomSink(zone_configuration_path=zone_configuration_path, classes=classes)
pipeline = InferencePipeline.init_with_custom_logic(
video_reference=rtsp_url,
on_video_frame=inference_callback,
on_prediction=sink.on_prediction,
)
pipeline.start()
try:
pipeline.join()
except KeyboardInterrupt:
pipeline.terminate()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculating detections dwell time in zones, using RTSP stream."
)
parser.add_argument(
"--zone_configuration_path",
type=str,
required=True,
help="Path to the zone configuration JSON file.",
)
parser.add_argument(
"--rtsp_url",
type=str,
required=True,
help="Complete RTSP URL for the video stream.",
)
parser.add_argument(
"--weights",
type=str,
default="yolov8s.pt",
help="Path to the model weights file. Default is 'yolov8s.pt'.",
)
parser.add_argument(
"--device",
type=str,
default="cpu",
help="Computation device ('cpu', 'mps' or 'cuda'). Default is 'cpu'.",
)
parser.add_argument(
"--confidence_threshold",
type=float,
default=0.3,
help="Confidence level for detections (0 to 1). Default is 0.3.",
)
parser.add_argument(
"--iou_threshold",
default=0.7,
type=float,
help="IOU threshold for non-max suppression. Default is 0.7.",
)
parser.add_argument(
"--classes",
nargs="*",
type=int,
default=[],
help="List of class IDs to track. If empty, all classes are tracked.",
)
args = parser.parse_args()
main(
rtsp_url=args.rtsp_url,
zone_configuration_path=args.zone_configuration_path,
weights=args.weights,
device=args.device,
confidence=args.confidence_threshold,
iou=args.iou_threshold,
classes=args.classes,
)
Loaded 100 of 192 files, more files were not shown because too many files have changed in this diff. Show more