Compare commits

..
89 Commits
Author SHA1 Message Date
SkalskiP 11197f8a4e bump version from 0.19.0rc2 to 0.19.0rc3 2024-02-09 18:09:56 +01:00
Piotr Skalski 8529a3ec18 Merge pull request #861 from NickHerrig/feat/cookbooks
Feat/cookbooks
2024-02-09 17:37:50 +01:00
SkalskiP 115d4492da changing colab names, card names, and card labels 2024-02-09 17:36:13 +01:00
Nick Herrig 84b54d31bf Add colab notebook button, test in notebooks 2024-02-09 10:34:40 -05:00
pre-commit-ci[bot] 57c7109498 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-09 14:30:00 +00:00
Nick Herrig 008dbcb0b4 Merge branch 'develop' into feat/cookbooks 2024-02-09 09:29:49 -05:00
Nick Herrig 122ca82cad Update cookbooks html to match new format -> no desc, cap tags 2024-02-09 09:27:07 -05:00
Nick Herrig 9ca7d3eb75 Finish and fix grammar of tracking cookbook 2024-02-09 09:21:14 -05:00
Piotr Skalski 5b2bdf58e7 Merge pull request #868 from roboflow/cookbooks/cards-improvements
[Cookbooks] - Improved functionality of cookbook cards
2024-02-09 14:24:51 +01:00
pre-commit-ci[bot] b7070ae574 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-09 13:23:07 +00:00
SkalskiP 85f09e3323 same label have same color across multiple cards; fixed small bug with hover effect 2024-02-09 14:19:41 +01:00
SkalskiP 03f7001a2b cookbooks-card.js refactor 2024-02-09 13:26:32 +01:00
SkalskiP 36a825b7a0 author styling improvements 2024-02-09 12:47:02 +01:00
Onuralp SEZER 0950f90ddf Merge pull request #867 from roboflow/dependabot/pip/nbconvert-7.16.0
⬆️ Bump nbconvert from 7.14.2 to 7.16.0
2024-02-09 14:22:44 +03:00
Onuralp SEZER cb22b94fe1 Merge pull request #866 from roboflow/dependabot/pip/ipywidgets-8.1.2
⬆️ Bump ipywidgets from 8.1.1 to 8.1.2
2024-02-09 14:22:29 +03:00
pre-commit-ci[bot] 019c41bf1a fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-09 04:37:54 +00:00
Nick Herrig 607d94dad9 Merge branch 'develop' into feat/cookbooks 2024-02-08 23:37:45 -05:00
Nick Herrig aacdbe76f0 Add html entries for cookbooks, add tracking cookbook 2024-02-08 23:27:53 -05:00
Nick Herrig f340c49a70 Update bounding box cookbook name, Fix grammar and spelling 2024-02-08 20:30:57 -05:00
dependabot[bot] 5bd30f4c72 ⬆️ Bump nbconvert from 7.14.2 to 7.16.0
Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 7.14.2 to 7.16.0.
- [Release notes](https://github.com/jupyter/nbconvert/releases)
- [Changelog](https://github.com/jupyter/nbconvert/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jupyter/nbconvert/compare/v7.14.2...v7.16.0)

---
updated-dependencies:
- dependency-name: nbconvert
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 01:04:56 +00:00
dependabot[bot] d0f31448b9 ⬆️ Bump ipywidgets from 8.1.1 to 8.1.2
Bumps [ipywidgets](https://github.com/jupyter-widgets/ipywidgets) from 8.1.1 to 8.1.2.
- [Release notes](https://github.com/jupyter-widgets/ipywidgets/releases)
- [Commits](https://github.com/jupyter-widgets/ipywidgets/compare/8.1.1...8.1.2)

---
updated-dependencies:
- dependency-name: ipywidgets
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 01:01:04 +00:00
Nick Herrig 7b4cf2f0f6 Reviewed supervision assets cookbook and renamed 2024-02-08 19:51:08 -05:00
Piotr Skalski fb7dd6aefd Merge pull request #865 from roboflow/cookbooks/html-optimization-and-css-update
cookbooks page HTML optimisation + CSS update
2024-02-08 22:42:00 +01:00
pre-commit-ci[bot] ce70266d23 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-08 21:39:07 +00:00
SkalskiP f1a2b99931 ready for review 2024-02-08 22:36:57 +01:00
Nick Herrig e3adcbeec1 Move cookbooks to new webpage and configure html file 2024-02-08 15:30:32 -05:00
SkalskiP 48af41377f move notebook inside the grid 2024-02-08 20:32:37 +01:00
Nick Herrig 0b7b8bb439 Move assets cookbook to docs, Update theme/cookbooks 2024-02-08 14:13:14 -05:00
Nick Herrig 95d28fabb5 Merge branch 'roboflow:develop' into feat/cookbooks 2024-02-08 13:30:40 -05:00
pre-commit-ci[bot] efd06ac77d fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-08 17:22:01 +00:00
Nick Herrig 1ac497a3e2 Finished bounding box annotation cookbook 2024-02-08 12:20:56 -05:00
Piotr Skalski 3dd3781b1b Add hackfest baner to README.md 2024-02-08 18:20:13 +01:00
Nick Herrig a015fc176e Fix object detection conflicts 2024-02-08 12:18:09 -05:00
Piotr Skalski 775c1b65f8 Merge pull request #863 from roboflow/fix/doc-env2
docs(fix): 🐞📝 MKDOCS_GIT_COMMITTERS_APIKEY fix attempt v2
2024-02-08 17:56:10 +01:00
Onuralp SEZER 8514f086b7 docs(fix): 🐞📝 MKDOCS_GIT_COMMITTERS_APIKEY fix attempt v2
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 19:53:51 +03:00
Nick Herrig 4685a0a2ff Update bounding box conflict 2024-02-08 11:38:14 -05:00
Piotr Skalski a26dd9416e Merge pull request #862 from roboflow/fix/doc-env
docs(fix): 🐞📝 MKDOCS_GIT_COMMITTERS_APIKEY value added
2024-02-08 17:37:57 +01:00
Onuralp SEZER a6466d13a9 docs(fix): 🐞📝 MKDOCS_GIT_COMMITTERS_APIKEY value added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 19:33:20 +03:00
Piotr Skalski 82b18ae3f8 Merge pull request #860 from roboflow/docs/notebooks
docs(page): 🚀 Supervision Cookbook
2024-02-08 17:26:24 +01:00
Onuralp SEZER 08a204d872 docs(api): 📝 api/annotators position adjusted and small typo fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 19:20:15 +03:00
Onuralp SEZER 4e5331b92d docs(version): 🐞 restore version part and revert hide h1 on home for now
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 18:57:39 +03:00
Onuralp SEZER 985624e35e docs(assets): 🐞 missing js and css files added into mkdocs.yml
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 18:05:07 +03:00
Onuralp SEZER 6a091b58a8 ci(docs): 👷 GH_TOKEN added for git-committers
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 17:51:19 +03:00
Onuralp SEZER 4ef2d04dec ci(docs): 👷 new packages added for build document
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 17:39:16 +03:00
pre-commit-ci[bot] f81ccbcc5f fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-08 14:34:47 +00:00
Onuralp SEZER d900e68787 docs(home): 🚀 hide table of content for home page only and give looks as more like home of supervision
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 17:33:52 +03:00
Onuralp SEZER ab38cb1531 docs(nb): 🚀 initial notebook added as quickstart and other examples are removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 17:30:04 +03:00
pre-commit-ci[bot] 7f51984063 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-08 14:22:52 +00:00
pre-commit-ci[bot] 1ad26b5527 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-08 14:13:38 +00:00
Onuralp SEZER d2ccc4f270 docs(nav): 🚀 nav-tab enabled and new order of pages for better understanding
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 17:13:03 +03:00
Onuralp SEZER 15b4914448 docs(js): 🔥 unused params has been removed from js files for cookbook page
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 17:06:22 +03:00
Onuralp SEZER 3ddeed1945 docs: ✨ data-url param added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 16:48:46 +03:00
Onuralp SEZER 1a20bb5745 docs: ✨ add demo notebook and remove notebooks folder from ignore list
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 16:33:05 +03:00
Onuralp SEZER c4365871b5 Merge changes from develop branch 2024-02-08 15:31:06 +03:00
Onuralp SEZER 1fba192319 docs: ✨ folder rename to javascript to javascripts (plural)
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 15:26:03 +03:00
Onuralp SEZER 6ffd159b77 docs: ✨ supervision cookbook initial page design landed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-08 15:20:43 +03:00
Onuralp SEZER 16d3214db9 Merge pull request #857 from roboflow/dependabot/pip/mkdocs-material-9.5.8
⬆️ Bump mkdocs-material from 9.5.7 to 9.5.8
2024-02-08 03:41:16 +03:00
dependabot[bot] 381bc8aed6 ⬆️ Bump mkdocs-material from 9.5.7 to 9.5.8
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.5.7 to 9.5.8.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.7...9.5.8)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-08 00:37:30 +00:00
Nick Herrig 3150f5a672 Add rough draft of bounding box displays 2024-02-07 18:55:24 -05:00
Onuralp SEZER eb35fdd1b7 Merge pull request #856 from roboflow/dependabot/pip/ruff-0.2.1
⬆️ Bump ruff from 0.2.0 to 0.2.1
2024-02-08 00:43:46 +03:00
Nick Herrig 9e95e1f0b3 Add supervision assets cookbook, correct assets documentation 2024-02-07 14:56:08 -05:00
Nick Herrig 4bfbe3c8f7 Add readme for cookbooks directory 2024-02-07 14:52:43 -05:00
Onuralp SEZER a6d9961b2b docs: ✨ jupyter notebook support added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-02-07 20:06:25 +03:00
Piotr Skalski a670faf646 Merge pull request #847 from AdonaiVera/segmentation_nms
[NMS] - add segmentation models support
2024-02-07 10:09:01 +01:00
SkalskiP 824a9140b6 tests fixed 2024-02-07 09:59:58 +01:00
SkalskiP 36ec1b6481 Merge remote-tracking branch 'origin/segmentation_nms' into segmentation_nms 2024-02-07 09:43:20 +01:00
SkalskiP 79a13d0432 final tests 2024-02-07 09:42:56 +01:00
pre-commit-ci[bot] cbbfb453f2 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-07 08:41:34 +00:00
SkalskiP bbe0bfc760 final tests 2024-02-07 09:41:21 +01:00
SkalskiP 98e7310038 test vectorized mask_non_max_suppression 2024-02-07 09:31:02 +01:00
SkalskiP 71836ed1ee Merge remote-tracking branch 'origin/segmentation_nms' into segmentation_nms 2024-02-07 09:28:03 +01:00
SkalskiP b681274954 Merge remote-tracking branch 'origin/segmentation_nms' into segmentation_nms 2024-02-07 09:27:49 +01:00
SkalskiP 619fa832c5 Merge remote-tracking branch 'origin/segmentation_nms' into segmentation_nms 2024-02-07 09:24:55 +01:00
SkalskiP f2e65cf6fc refactored mask_non_max_suppression 2024-02-07 09:24:45 +01:00
pre-commit-ci[bot] 8f6887d994 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-07 08:21:36 +00:00
SkalskiP c46a2e9c08 Merge remote-tracking branch 'origin/segmentation_nms' into segmentation_nms
# Conflicts:
#	supervision/detection/utils.py
2024-02-07 09:21:22 +01:00
SkalskiP 7e44838e51 refactored mask_non_max_suppression 2024-02-07 09:20:54 +01:00
pre-commit-ci[bot] c98dbbf2f6 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-07 08:18:54 +00:00
SkalskiP 239f7333f1 refactored mask_non_max_suppression 2024-02-07 09:18:41 +01:00
SkalskiP 35c9ebdd60 refactored mask_non_max_suppression 2024-02-07 08:51:57 +01:00
pre-commit-ci[bot] 879cf6d9dc fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-07 05:15:10 +00:00
Adonai Vera fd70f3ce5d Applied inclusion-exclusion principle to mask_iou_batch and resize function to improve speed 2024-02-07 00:14:54 -05:00
pre-commit-ci[bot] cf63c838b2 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-06 08:55:15 +00:00
SkalskiP 9ee42e5257 mask_iou_batch speed test 2024-02-06 09:54:07 +01:00
dependabot[bot] 9253da570f ⬆️ Bump ruff from 0.2.0 to 0.2.1
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/v0.2.0...v0.2.1)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-06 01:03:21 +00:00
pre-commit-ci[bot] 1e87a99259 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-03 03:19:57 +00:00
Adonai Vera ebe2785287 Removed issue of length sentence 2024-02-02 22:19:40 -05:00
pre-commit-ci[bot] aaf3621841 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-02-03 03:10:29 +00:00
Adonai Vera 6a9c013949 Added nms for segmentation algorithm, added unit test, added init, added withnms conditional depends if contains mask 2024-02-02 21:33:15 -05:00
29 changed files with 2844 additions and 107 deletions
+11 -3
View File
@@ -21,19 +21,27 @@ jobs:
- name: 🐍 Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.x
python-version: '3.10'
- name: 📦 Install mkdocs-material
run: pip 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: ⚙️ 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: |
mike deploy --push develop
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} mike deploy --push develop
-3
View File
@@ -133,9 +133,6 @@ dmypy.json
# Pyre type checker
.pyre/
# Notebooks
notebooks/
# OSX folder attributes
.DS_Store
.AppleDouble
+3 -1
View File
@@ -21,13 +21,15 @@
[![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>
## 👋 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
+19
View File
@@ -0,0 +1,19 @@
# Supervision Cookbooks
## About
The Roboflow Cookbook is an open-source collection of examples and guides for building with the [Roboflow Ecosystem](https://roboflow.com/).
Cookbooks are meant to be common and small scoped computer vision tasks that can allow a user to quickly hit the ground running. Learning is the main goal and purpose.
Some examples require a Roboflow API key. You can [create a free account here](https://app.roboflow.com/login).
## Other Resources
Other than Cookbooks, Roboflow offers other learning resources including:
- A set of open source tools found on [Github](https://github.com/roboflow).
- A [blog](https://blog.roboflow.com/) detailing interesting tutorials, computer vision news, and product updates.
- A [Youtube channel](https://www.youtube.com/roboflow) with end to end commputer vision projects.
- A [forum](https://discuss.roboflow.com/) for sharing feedback, discussions, and other questions.
- The worlds largest [open source collection](https://universe.roboflow.com/) of images, datasets, and fine-tuned models.
Vendored
+17 -5
View File
@@ -12,11 +12,23 @@
"\n",
"---\n",
"\n",
"[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision)\n",
"[![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision)\n",
"[![license](https://img.shields.io/pypi/l/supervision)](https://github.com/roboflow/supervision/blob/main/LICENSE.md)\n",
"[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)\n",
"[![GitHub](https://badges.aleen42.com/src/github.svg)](https://github.com/roboflow/supervision)\n",
"<p align=\"center\">\n",
" <a href=\"https://badge.fury.io/py/supervision\"><img src=\"https://badge.fury.io/py/supervision.svg\" alt=\"version\"></a>\n",
" <a href=\"https://pypistats.org/packages/supervision\"><img src=\"https://img.shields.io/pypi/dm/supervision\" alt=\"downloads\"></a>\n",
" <a href=\"https://github.com/roboflow/supervision/blob/main/LICENSE.md\"><img src=\"https://img.shields.io/pypi/l/supervision\" alt=\"license\"></a>\n",
" <a href=\"https://badge.fury.io/py/supervision\"><img src=\"https://img.shields.io/pypi/pyversions/supervision\" alt=\"python-version\"></a>\n",
" <a href=\"https://github.com/roboflow/supervision\"><img src=\"https://badges.aleen42.com/src/github.svg\" alt=\"GitHub\"></a>\n",
"</p>\n",
"\n",
"<p align=\"center\">\n",
" <a href=\"https://colab.research.google.com/github/roboflow/supervision/blob/main/demo.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Colab\"></a>\n",
" <a href=\"https://kaggle.com/kernels/welcome?src=https://github.com/roboflow/supervision/blob/main/demo.ipynb\"><img src=\"https://kaggle.com/static/images/open-in-kaggle.svg\" alt=\"Kaggle\"></a>\n",
" <a href=\"https://studiolab.sagemaker.aws/import/github/roboflow/supervision/blob/main/demo.ipynb\"><img src=\"https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/sage-maker.svg\" alt=\"SageMaker\"></a>\n",
" <a href=\"https://nbviewer.jupyter.org/github/roboflow/supervision/blob/main/demo.ipynb\"><img src=\"https://img.shields.io/badge/Open_in_Nbviewer-F37626.svg?logo=Jupyter&logoColor=white\" alt=\"nbviewer\">\n",
" <a href=\"https://mybinder.org/v2/gh/roboflow/supervision/develop?labpath=demo.ipynb\"><img src=\"https://mybinder.org/badge_logo.svg\" alt=\"Binder\"></a>\n",
" <a href=\"https://github.com/roboflow/supervision/raw/main/demo.ipynb\" download><img src=\"https://img.shields.io/badge/Download-Notebook-A351FB.svg\" alt=\"Download\"></a>\n",
"</p>\n",
"\n",
"\n",
"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! 🤝\n",
"\n",
+2 -3
View File
@@ -7,8 +7,7 @@ comments: true
Supervision offers an assets download utility that allows you to download video files
that you can use in your demos.
## install extra
## Install extra
To install the Supervision assets utility, you can use `pip`. This utility is available
as an extra within the Supervision package.
@@ -16,7 +15,7 @@ as an extra within the Supervision package.
!!! example "pip install"
```bash
pip install supervision[assets]
pip install "supervision[assets]"
```
<div class="md-typeset">
+1 -1
View File
@@ -1,6 +1,6 @@
### 0.18.0 <small>January 25, 2024</small>
- Added [#633](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.
- Added [#633](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
+8
View File
@@ -0,0 +1,8 @@
---
template: cookbooks.html
comments: true
status: new
hide:
- navigation
- toc
---
+14 -2
View File
@@ -11,10 +11,22 @@ comments: true
:::supervision.detection.utils.box_iou_batch
<div class="md-typeset">
<h2>non_max_suppression</h2>
<h2>mask_iou_batch</h2>
</div>
:::supervision.detection.utils.non_max_suppression
:::supervision.detection.utils.mask_iou_batch
<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>
+11 -11
View File
@@ -44,7 +44,7 @@ Now that we have predictions from a model, we can load them into Supervision.
=== "Ultralytics"
We can do so using the [`sv.Detections.from_ultralytics`](/latest/detection/core/#supervision.detection.core.Detections.from_ultralytics) method, which accepts model results from both detection and segmentation models.
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.
```python
import cv2
@@ -59,7 +59,7 @@ 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`](/latest/detection/core/#supervision.detection.core.Detections.from_inference) method, which accepts model results from both detection and segmentation models.
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.
```python
import cv2
@@ -74,17 +74,17 @@ Now that we have predictions from a model, we can load them into Supervision.
You can conveniently 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_inference`](/latest/detection/core/#supervision.detection.core.Detections.from_inference) ([Roboflow Inference](https://github.com/roboflow/inference))
- [`from_sam`](/latest/detection/core/#supervision.detection.core.Detections.from_sam) ([Segment Anything Model](https://github.com/facebookresearch/segment-anything))
- [`from_transformers`](/latest/detection/core/#supervision.detection.core.Detections.from_transformers) ([HuggingFace Transformers](https://github.com/huggingface/transformers))
- [`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))
- [`from_deepsparse`](detection/core/#supervision.detection.core.Detections.from_deepsparse) ([Deepsparse](https://github.com/neuralmagic/deepsparse))
- [`from_detectron2`](detection/core/#supervision.detection.core.Detections.from_detectron2) ([Detectron2](https://github.com/facebookresearch/detectron2))
- [`from_mmdetection`](detection/core/#supervision.detection.core.Detections.from_mmdetection) ([MMDetection](https://github.com/open-mmlab/mmdetection))
- [`from_inference`](detection/core/#supervision.detection.core.Detections.from_inference) ([Roboflow Inference](https://github.com/roboflow/inference))
- [`from_sam`](detection/core/#supervision.detection.core.Detections.from_sam) ([Segment Anything Model](https://github.com/facebookresearch/segment-anything))
- [`from_transformers`](detection/core/#supervision.detection.core.Detections.from_transformers) ([HuggingFace Transformers](https://github.com/huggingface/transformers))
- [`from_yolo_nas`](detection/core/#supervision.detection.core.Detections.from_yolo_nas) ([YOLO-NAS](https://github.com/Deci-AI/super-gradients/blob/master/YOLONAS.md))
## Annotate Image
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. 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.
Finally, we can annotate the image with the predictions. Since we are working with an object detection model, we will use the [`sv.BoundingBoxAnnotator`](annotators/#supervision.annotators.core.BoundingBoxAnnotator) and [`sv.LabelAnnotator`](annotators/#supervision.annotators.core.LabelAnnotator) classes. If you are running the segmentation model [`sv.MaskAnnotator`](annotators/#supervision.annotators.core.MaskAnnotator) is a drop-in replacement for [`sv.BoundingBoxAnnotator`](annotators/#supervision.annotators.core.BoundingBoxAnnotator) that will allow you to draw masks instead of boxes.
=== "Ultralytics"
@@ -138,7 +138,7 @@ Finally, we can annotate the image with the predictions. Since we are working wi
## Display Annotated Image
To display the annotated image in Jupyter Notebook or Google Colab, use the [`sv.plot_image`](/latest/utils/notebook/#supervision.utils.notebook.plot_image) function.
To display the annotated image in Jupyter Notebook or Google Colab, use the [`sv.plot_image`](utils/notebook/#supervision.utils.notebook.plot_image) function.
```python
sv.plot_image(annotated_image)
+3
View File
@@ -1,5 +1,8 @@
---
comments: true
hide:
- navigation
- toc
---
<div align="center">
+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 = 100 - 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);
});
})
+208
View File
@@ -0,0 +1,208 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# How to Display Bounding Boxes on Objects in a Video.\n",
"\n",
"---\n",
"\n",
"<p align=\"center\">\n",
" <a href=\"https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/bounding-boxes.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Colab\"></a>\n",
"</p>\n",
"\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! \n",
"\n",
"## 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": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"\n",
"!pip install -q inference \"supervision[assets]\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"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. Wehn 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": {},
"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": {},
"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": null,
"metadata": {},
"outputs": [],
"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",
"if __name__ == \"__main__\":\n",
" # Download the video asset from Supervision assets.\n",
" PATH_TO_VIDEO = download_assets(VideoAssets.PEOPLE_WALKING)\n",
"\n",
" # Load a yolov8 nano model from roboflow.\n",
" model = get_roboflow_model(\"yolov8n-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",
" # Display the detections data model.\n",
" print(detections)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"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, then 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! \n",
"\n",
"## Saving Bounding Boxes to the Video\n",
"\n",
"Now comes the fun part. Let's wrap up our code by utilizing `Annotators` and a `VideoSink` to draw bounding boxes and save the resulting video respectively. Take a peak at the final code example below. This might can take up to a minute to run, since we're processing a full video. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"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",
"if __name__ == \"__main__\":\n",
" # Download the video asset from Supervision assets.\n",
" PATH_TO_VIDEO = download_assets(VideoAssets.PEOPLE_WALKING)\n",
"\n",
" # Load a yolov8 nano model from roboflow.\n",
" model = get_roboflow_model(\"yolov8n-640\")\n",
"\n",
" # Initalize the bounding box frame annotator.\n",
" box_annotator = sv.BoundingBoxAnnotator()\n",
"\n",
" # Create a frame generator object from video path.\n",
" frame_generator = sv.get_video_frames_generator(PATH_TO_VIDEO)\n",
"\n",
" # Create a video info object from video path.\n",
" video_info = sv.VideoInfo.from_video_path(PATH_TO_VIDEO)\n",
"\n",
" # Use a VideoSink context manager for saving frames of a 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 frame_generator:\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 = box_annotator.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": {},
"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. Next, we create 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. Prior to writing the frame, we annotate a copy of it utilizing `box_annotator.annotate()`. Let's take a look at the resulting video. It will be installed locally and is called `output.mp4`. When run, you will see bounding boxes around the detections. Pretty awesome! "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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! "
]
}
],
"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.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
+99
View File
@@ -0,0 +1,99 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Experimenting with Supervision Assets\n",
"\n",
"---\n",
"\n",
"<p align=\"center\">\n",
" <a href=\"https://colab.research.google.com/github/roboflow/supervision/blob/develop/docs/notebooks/supervision-assets.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Colab\"></a>\n",
"</p>\n",
"\n",
"When experimenting with interesting and useful features of the Supervision package, its 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 with Pip\n",
"\n",
"If you're running this code outside a Jupyter notebook, it's generally a best practice to create a virtual environment so that your projects deppendencies are isolated. Run the following ing your command line of choice to create and source one.\n",
"\n",
"```shell\n",
"\n",
"python -m venv venv\n",
"source venv/bin/activate\n",
"\n",
"``` "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we've got a virtual enviornment installed and sourced, let's install the pip package with the assets \"extra\" package. Make sure to remove the \"!\" if running this in your command line."
]
},
{
"cell_type": "code",
"execution_count": null,
"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 a video asset from the supervision package.\n",
"path_to_video = download_assets(VideoAssets.SUBWAY)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're now equipt with a video asset from Supervision to run some experiements on! For more information on available video assets, visit the [Supervision API Reference](https://supervision.roboflow.com/latest/assets/#videoassets). 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.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
+154
View File
@@ -0,0 +1,154 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tracking Objects in a Video\n",
"\n",
"---\n",
"\n",
"<p align=\"center\">\n",
" <a href=\"https://colab.research.google.com/github/roboflow/supervision/blob/main/docs/notebooks/tracking.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Colab\"></a>\n",
"</p>\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 Supvervision [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. But first, let's get our deppendencies installed. \n",
"\n",
"## Install Dependencies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "powershell"
}
},
"outputs": [],
"source": [
"!pip install -q inference \"supervision[assets]\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"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": {},
"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": {},
"source": [
"## Tracking Objects\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. 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": {},
"outputs": [],
"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",
"if __name__ == '__main__':\n",
"\n",
" # Install our video from supervision assets.\n",
" PATH_TO_VIDEO = download_assets(VideoAssets.PEOPLE_WALKING)\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 over frames of the video.\n",
" for frame in 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",
" # Save the annotated frame to an output video.\n",
" sink.write_frame(frame=annotated_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# View the Video\n",
"\n",
"Let's take a look at our resulting video. It will 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! "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "venv",
"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.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
+1355
View File
File diff suppressed because one or more lines are too long
+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%;
}
+21
View File
@@ -0,0 +1,21 @@
{% 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/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>
</div>
</div>
</section>
{% endblock %}
+12 -1
View File
@@ -1,5 +1,16 @@
{% 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>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>
{% endblock %}
+41 -10
View File
@@ -31,6 +31,8 @@ extra:
extra_css:
- stylesheets/extra.css
- stylesheets/cookbooks-card.css
nav:
- Home: index.md
@@ -39,6 +41,7 @@ nav:
- Track Objects: how_to/track_objects.md
- Filter Detections: how_to/filter_detections.md
- API:
- Annotators: annotators.md
- Classifications:
- Core: classification/core.md
- Detections:
@@ -50,7 +53,6 @@ nav:
- Inference Slicer: detection/tools/inference_slicer.md
- Detection Smoother: detection/tools/smoother.md
- Save Detections: detection/tools/save_detections.md
- Annotators: annotators.md
- Trackers: trackers.md
- Datasets: datasets.md
- Metrics:
@@ -65,21 +67,33 @@ nav:
- Image: utils/image.md
- Notebook: utils/notebook.md
- File: utils/file.md
- Assets: assets.md
- Development:
- Assets: assets.md
- Cookbooks: cookbooks.md
- Contribute:
- Contributing: contributing.md
- Code of Conduct: code_of_conduct.md
- License: license.md
- Changelog:
- Changelog: changelog.md
- Deprecated: deprecated.md
- License: license.md
theme:
name: 'material'
icon:
edit: material/pencil
logo: assets/supervision-lenny.png
favicon: assets/supervision-lenny.png
custom_dir: docs/theme
features:
- navigation.tracking
- content.code.copy
- content.action.edit
- content.tooltips
- content.code.annotate
- navigation.tabs
palette:
# Palette for light mode
- scheme: default
@@ -94,15 +108,22 @@ theme:
toggle:
icon: material/brightness-4
name: Switch to light mode
font:
text: Roboto
code: Roboto Mono
features:
- content.code.copy
- content.code.annotate
features:
- content.code.copy
- content.code.annotate
plugins:
- search
- mkdocs-jupyter:
kernel_name: python3
execute: false
include_source: True
include_requirejs: true
- mkdocstrings:
default_handler: python
handlers:
@@ -118,9 +139,15 @@ plugins:
show_symbol_type_heading: true
show_symbol_type_toc: true
show_category_heading: true
import:
- https://docs.python-requests.org/en/master/objects.inv
domains: [std, py]
- git-committers:
repository: roboflow/supervision
branch: develop
token: !ENV ["GITHUB_TOKEN"]
- git-revision-date-localized:
enable_creation_date: true
markdown_extensions:
- admonition
@@ -137,7 +164,11 @@ markdown_extensions:
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.snippets:
check_paths: true
- pymdownx.highlight:
anchor_linenums: true
extra_javascript:
- "https://widget.kapa.ai/kapa-widget.bundle.js"
- "javascript/init_kapa_widget.js"
- "javascripts/init_kapa_widget.js"
- "javascripts/cookbooks-card.js"
- "https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.8/purify.min.js"
Generated
+228 -43
View File
@@ -984,6 +984,37 @@ python-dateutil = ">=2.8.1"
[package.extras]
dev = ["flake8", "markdown", "twine", "wheel"]
[[package]]
name = "gitdb"
version = "4.0.11"
description = "Git Object Database"
optional = false
python-versions = ">=3.7"
files = [
{file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"},
{file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"},
]
[package.dependencies]
smmap = ">=3.0.1,<6"
[[package]]
name = "gitpython"
version = "3.1.41"
description = "GitPython is a Python library used to interact with Git repositories"
optional = false
python-versions = ">=3.7"
files = [
{file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"},
{file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"},
]
[package.dependencies]
gitdb = ">=4.0.1,<5"
[package.extras]
test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"]
[[package]]
name = "griffe"
version = "0.39.1"
@@ -1143,6 +1174,27 @@ qtconsole = ["qtconsole"]
test = ["pytest (<7.1)", "pytest-asyncio", "testpath"]
test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"]
[[package]]
name = "ipywidgets"
version = "8.1.2"
description = "Jupyter interactive widgets"
optional = false
python-versions = ">=3.7"
files = [
{file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"},
{file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"},
]
[package.dependencies]
comm = ">=0.1.3"
ipython = ">=6.1.0"
jupyterlab-widgets = ">=3.0.10,<3.1.0"
traitlets = ">=4.3.1"
widgetsnbextension = ">=4.0.10,<4.1.0"
[package.extras]
test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"]
[[package]]
name = "isoduration"
version = "20.11.0"
@@ -1157,20 +1209,6 @@ files = [
[package.dependencies]
arrow = ">=0.15.0"
[[package]]
name = "isort"
version = "5.13.2"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
files = [
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
]
[package.extras]
colors = ["colorama (>=0.4.6)"]
[[package]]
name = "jaraco-classes"
version = "3.3.0"
@@ -1519,6 +1557,46 @@ docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pyd
openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"]
test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"]
[[package]]
name = "jupyterlab-widgets"
version = "3.0.10"
description = "Jupyter interactive widgets for JupyterLab"
optional = false
python-versions = ">=3.7"
files = [
{file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"},
{file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"},
]
[[package]]
name = "jupytext"
version = "1.16.1"
description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts"
optional = false
python-versions = ">=3.8"
files = [
{file = "jupytext-1.16.1-py3-none-any.whl", hash = "sha256:796ec4f68ada663569e5d38d4ef03738a01284bfe21c943c485bc36433898bd0"},
{file = "jupytext-1.16.1.tar.gz", hash = "sha256:68c7b68685e870e80e60fda8286fbd6269e9c74dc1df4316df6fe46eabc94c99"},
]
[package.dependencies]
markdown-it-py = ">=1.0"
mdit-py-plugins = "*"
nbformat = "*"
packaging = "*"
pyyaml = "*"
toml = "*"
[package.extras]
dev = ["jupytext[test-cov,test-external]"]
docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"]
test = ["pytest", "pytest-randomly", "pytest-xdist"]
test-cov = ["jupytext[test-integration]", "pytest-cov (>=2.6.1)"]
test-external = ["autopep8", "black", "flake8", "gitpython", "isort", "jupyter-fs (<0.4.0)", "jupytext[test-integration]", "pre-commit", "sphinx-gallery (<0.8)"]
test-functional = ["jupytext[test]"]
test-integration = ["ipykernel", "jupyter-server (!=2.11)", "jupytext[test-functional]", "nbconvert"]
test-ui = ["calysto-bash"]
[[package]]
name = "keyring"
version = "24.3.0"
@@ -1849,6 +1927,25 @@ files = [
[package.dependencies]
traitlets = "*"
[[package]]
name = "mdit-py-plugins"
version = "0.4.0"
description = "Collection of plugins for markdown-it-py"
optional = false
python-versions = ">=3.8"
files = [
{file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"},
{file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"},
]
[package.dependencies]
markdown-it-py = ">=1.0.0,<4.0.0"
[package.extras]
code-style = ["pre-commit"]
rtd = ["myst-parser", "sphinx-book-theme"]
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
[[package]]
name = "mdurl"
version = "0.1.2"
@@ -1952,15 +2049,70 @@ files = [
Markdown = ">=3.3"
mkdocs = ">=1.1"
[[package]]
name = "mkdocs-git-committers-plugin-2"
version = "2.2.3"
description = "An MkDocs plugin to create a list of contributors on the page. The git-committers plugin will seed the template context with a list of GitHub or GitLab committers and other useful GIT info such as last modified date"
optional = false
python-versions = ">=3.8,<4"
files = [
{file = "mkdocs-git-committers-plugin-2-2.2.3.tar.gz", hash = "sha256:e0dddef4e3e321d97bcb83123fd963a839d9f9fa801c3125efeb6544bd8b247c"},
{file = "mkdocs_git_committers_plugin_2-2.2.3-py3-none-any.whl", hash = "sha256:0f20d61a9315174f30d5a0266d4a457d3d88909ca5c5bd7d0e0dd2e1841f2af0"},
]
[package.dependencies]
gitpython = "*"
mkdocs = ">=1.0.3"
requests = "*"
[[package]]
name = "mkdocs-git-revision-date-localized-plugin"
version = "1.2.4"
description = "Mkdocs plugin that enables displaying the localized date of the last git modification of a markdown file."
optional = false
python-versions = ">=3.8"
files = [
{file = "mkdocs-git-revision-date-localized-plugin-1.2.4.tar.gz", hash = "sha256:08fd0c6f33c8da9e00daf40f7865943113b3879a1c621b2bbf0fa794ffe997d3"},
{file = "mkdocs_git_revision_date_localized_plugin-1.2.4-py3-none-any.whl", hash = "sha256:1f94eb510862ef94e982a2910404fa17a1657ecf29f45a07b0f438c00767fc85"},
]
[package.dependencies]
babel = ">=2.7.0"
GitPython = "*"
mkdocs = ">=1.0"
pytz = "*"
[[package]]
name = "mkdocs-jupyter"
version = "0.24.3"
description = "Use Jupyter in mkdocs websites"
optional = false
python-versions = ">=3.7"
files = [
{file = "mkdocs_jupyter-0.24.3-py3-none-any.whl", hash = "sha256:904262a8678a5e5920b7c3c03b5010b36301a69d0a38f2fcbf430493adf6879e"},
{file = "mkdocs_jupyter-0.24.3.tar.gz", hash = "sha256:3d81da9aea27480e93bab22438910c4f0b9630613e74f85b576590d78e0e8b14"},
]
[package.dependencies]
ipykernel = ">6.0.0,<7.0.0"
jupytext = ">1.13.8,<2"
mkdocs = ">=1.4.0,<2"
mkdocs-material = ">9.0.0"
nbconvert = ">=7.2.9,<8"
pygments = ">2.12.0"
[package.extras]
test = ["coverage[toml]", "pymdown-extensions", "pytest", "pytest-cov"]
[[package]]
name = "mkdocs-material"
version = "9.5.7"
version = "9.5.8"
description = "Documentation that simply works"
optional = false
python-versions = ">=3.8"
files = [
{file = "mkdocs_material-9.5.7-py3-none-any.whl", hash = "sha256:0be8ce8bcfebb52bae9b00cf9b851df45b8a92d629afcfd7f2c09b2dfa155ea3"},
{file = "mkdocs_material-9.5.7.tar.gz", hash = "sha256:16110292575d88a338d2961f3cb665cf12943ff8829e551a9b364f24019e46af"},
{file = "mkdocs_material-9.5.8-py3-none-any.whl", hash = "sha256:14563314bbf97da4bfafc69053772341babfaeb3329cde01d3e63cec03997af8"},
{file = "mkdocs_material-9.5.8.tar.gz", hash = "sha256:2a429213e83f84eda7a588e2b186316d806aac602b7f93990042f7a1f3d3cf65"},
]
[package.dependencies]
@@ -1979,7 +2131,7 @@ regex = ">=2022.4"
requests = ">=2.26,<3.0"
[package.extras]
git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2,<2.0)"]
git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"]
imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"]
recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"]
@@ -2131,13 +2283,13 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=
[[package]]
name = "nbconvert"
version = "7.14.2"
version = "7.16.0"
description = "Converting Jupyter Notebooks"
optional = false
python-versions = ">=3.8"
files = [
{file = "nbconvert-7.14.2-py3-none-any.whl", hash = "sha256:db28590cef90f7faf2ebbc71acd402cbecf13d29176df728c0a9025a49345ea1"},
{file = "nbconvert-7.14.2.tar.gz", hash = "sha256:a7f8808fd4e082431673ac538400218dd45efd076fbeb07cc6e5aa5a3a4e949e"},
{file = "nbconvert-7.16.0-py3-none-any.whl", hash = "sha256:ad3dc865ea6e2768d31b7eb6c7ab3be014927216a5ece3ef276748dd809054c7"},
{file = "nbconvert-7.16.0.tar.gz", hash = "sha256:813e6553796362489ae572e39ba1bff978536192fb518e10826b0e8cadf03ec8"},
]
[package.dependencies]
@@ -2840,13 +2992,13 @@ files = [
[[package]]
name = "pytz"
version = "2023.3.post1"
version = "2024.1"
description = "World timezone definitions, modern and historical"
optional = false
python-versions = "*"
files = [
{file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
{file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
{file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"},
{file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"},
]
[[package]]
@@ -3416,28 +3568,28 @@ files = [
[[package]]
name = "ruff"
version = "0.2.0"
version = "0.2.1"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.2.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:638ea3294f800d18bae84a492cb5a245c8d29c90d19a91d8e338937a4c27fca0"},
{file = "ruff-0.2.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3ff35433fcf4dff6d610738712152df6b7d92351a1bde8e00bd405b08b3d5759"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9faafbdcf4f53917019f2c230766da437d4fd5caecd12ddb68bb6a17d74399"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8153a3e4128ed770871c47545f1ae7b055023e0c222ff72a759f5a341ee06483"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8a75a98ae989a27090e9c51f763990ad5bbc92d20626d54e9701c7fe597f399"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:87057dd2fdde297130ff99553be8549ca38a2965871462a97394c22ed2dfc19d"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d232f99d3ab00094ebaf88e0fb7a8ccacaa54cc7fa3b8993d9627a11e6aed7a"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d3c641f95f435fc6754b05591774a17df41648f0daf3de0d75ad3d9f099ab92"},
{file = "ruff-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3826fb34c144ef1e171b323ed6ae9146ab76d109960addca730756dc19dc7b22"},
{file = "ruff-0.2.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:eceab7d85d09321b4de18b62d38710cf296cb49e98979960a59c6b9307c18cfe"},
{file = "ruff-0.2.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:30ad74687e1f4a9ff8e513b20b82ccadb6bd796fe5697f1e417189c5cde6be3e"},
{file = "ruff-0.2.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a7e3818698f8460bd0f8d4322bbe99db8327e9bc2c93c789d3159f5b335f47da"},
{file = "ruff-0.2.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:edf23041242c48b0d8295214783ef543847ef29e8226d9f69bf96592dba82a83"},
{file = "ruff-0.2.0-py3-none-win32.whl", hash = "sha256:e155147199c2714ff52385b760fe242bb99ea64b240a9ffbd6a5918eb1268843"},
{file = "ruff-0.2.0-py3-none-win_amd64.whl", hash = "sha256:ba918e01cdd21e81b07555564f40d307b0caafa9a7a65742e98ff244f5035c59"},
{file = "ruff-0.2.0-py3-none-win_arm64.whl", hash = "sha256:3fbaff1ba9564a2c5943f8f38bc221f04bac687cc7485e45237579fee7ccda79"},
{file = "ruff-0.2.0.tar.gz", hash = "sha256:63856b91837606c673537d2889989733d7dffde553828d3b0f0bacfa6def54be"},
{file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:dd81b911d28925e7e8b323e8d06951554655021df8dd4ac3045d7212ac4ba080"},
{file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dc586724a95b7d980aa17f671e173df00f0a2eef23f8babbeee663229a938fec"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c92db7101ef5bfc18e96777ed7bc7c822d545fa5977e90a585accac43d22f18a"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13471684694d41ae0f1e8e3a7497e14cd57ccb7dd72ae08d56a159d6c9c3e30e"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a11567e20ea39d1f51aebd778685582d4c56ccb082c1161ffc10f79bebe6df35"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:00a818e2db63659570403e44383ab03c529c2b9678ba4ba6c105af7854008105"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be60592f9d218b52f03384d1325efa9d3b41e4c4d55ea022cd548547cc42cd2b"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbd2288890b88e8aab4499e55148805b58ec711053588cc2f0196a44f6e3d855"},
{file = "ruff-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ef052283da7dec1987bba8d8733051c2325654641dfe5877a4022108098683"},
{file = "ruff-0.2.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7022d66366d6fded4ba3889f73cd791c2d5621b2ccf34befc752cb0df70f5fad"},
{file = "ruff-0.2.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0a725823cb2a3f08ee743a534cb6935727d9e47409e4ad72c10a3faf042ad5ba"},
{file = "ruff-0.2.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0034d5b6323e6e8fe91b2a1e55b02d92d0b582d2953a2b37a67a2d7dedbb7acc"},
{file = "ruff-0.2.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e5cb5526d69bb9143c2e4d2a115d08ffca3d8e0fddc84925a7b54931c96f5c02"},
{file = "ruff-0.2.1-py3-none-win32.whl", hash = "sha256:6b95ac9ce49b4fb390634d46d6ece32ace3acdd52814671ccaf20b7f60adb232"},
{file = "ruff-0.2.1-py3-none-win_amd64.whl", hash = "sha256:e3affdcbc2afb6f5bd0eb3130139ceedc5e3f28d206fe49f63073cb9e65988e0"},
{file = "ruff-0.2.1-py3-none-win_arm64.whl", hash = "sha256:efababa8e12330aa94a53e90a81eb6e2d55f348bc2e71adbf17d9cad23c03ee6"},
{file = "ruff-0.2.1.tar.gz", hash = "sha256:3b42b5d8677cd0c72b99fcaf068ffc62abb5a19e71b4a3b9cfa50658a0af02f1"},
]
[[package]]
@@ -3578,6 +3730,17 @@ files = [
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[[package]]
name = "smmap"
version = "5.0.1"
description = "A pure Python implementation of a sliding window memory map manager"
optional = false
python-versions = ">=3.7"
files = [
{file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"},
{file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"},
]
[[package]]
name = "sniffio"
version = "1.3.0"
@@ -3658,6 +3821,17 @@ webencodings = ">=0.4"
doc = ["sphinx", "sphinx_rtd_theme"]
test = ["flake8", "isort", "pytest"]
[[package]]
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
[[package]]
name = "tomli"
version = "2.0.1"
@@ -3965,6 +4139,17 @@ files = [
[package.extras]
test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
[[package]]
name = "widgetsnbextension"
version = "4.0.10"
description = "Jupyter interactive widgets for Jupyter Notebook"
optional = false
python-versions = ">=3.7"
files = [
{file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"},
{file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"},
]
[[package]]
name = "zipp"
version = "3.17.0"
@@ -3987,4 +4172,4 @@ desktop = ["opencv-python"]
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
content-hash = "07b8d86e8a1e4688ed81283e49b3969889b5374ca079cbafc1b4b7038b01b949"
content-hash = "8345f7320402678ec689446421f80bff7fdb3fc13247269346c5ba3daf83ba7b"
+12 -6
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "supervision"
version = "0.19.0rc2"
version = "0.19.0rc3"
description = "A set of easy-to-use utils that will come in handy in any Computer Vision project"
authors = ["Piotr Skalski <piotr.skalski92@gmail.com>"]
maintainers = ["Piotr Skalski <piotr.skalski92@gmail.com>"]
@@ -39,13 +39,11 @@ scipy = [
]
matplotlib = ">=3.6.0"
pyyaml = ">=5.3"
defusedxml = "^0.7.1"
opencv-python = { version = ">=4.5.5.64", optional = true }
opencv-python-headless = ">=4.5.5.64"
requests = { version = ">=2.26.0,<=2.31.0", optional = true }
tqdm = { version = ">=4.62.3,<=4.66.1", optional = true }
defusedxml = "^0.7.1"
[tool.poetry.extras]
desktop = ["opencv-python"]
@@ -55,19 +53,27 @@ assets = ["requests","tqdm"]
twine = "^4.0.2"
pytest = ">=7.2.2,<9.0.0"
wheel = ">=0.40,<0.43"
notebook = ">=6.5.3,<8.0.0"
build = ">=0.10,<1.1"
ruff = ">=0.1.0"
isort = "^5.12.0"
mypy = "^1.4.1"
pre-commit = "^3.3.3"
tox = "^4.11.4"
notebook = ">=6.5.3,<8.0.0"
ipywidgets = "^8.1.1"
jupytext = "^1.16.1"
nbconvert = "^7.14.2"
[tool.poetry.group.docs.dependencies]
mkdocs-material = {extras = ["imaging"], version = "^9.5.5"}
mkdocstrings = {extras = ["python"], version = ">=0.20,<0.25"}
mike = "^2.0.0"
# For Documentation Development use Python 3.10 or above
# Use Latest mkdocs-jupyter min 0.24.6 for Jupyter Notebook Theme support
mkdocs-jupyter = "^0.24.3"
mkdocs-git-committers-plugin-2 = "^2.2.3"
mkdocs-git-revision-date-localized-plugin = "^1.2.4"
[tool.isort]
+3 -1
View File
@@ -42,12 +42,14 @@ from supervision.detection.tools.polygon_zone import PolygonZone, PolygonZoneAnn
from supervision.detection.tools.smoother import DetectionsSmoother
from supervision.detection.utils import (
box_iou_batch,
box_non_max_suppression,
calculate_masks_centroids,
filter_polygons_by_area,
mask_iou_batch,
mask_non_max_suppression,
mask_to_polygons,
mask_to_xyxy,
move_boxes,
non_max_suppression,
polygon_to_mask,
polygon_to_xyxy,
scale_boxes,
+23 -13
View File
@@ -8,12 +8,13 @@ import numpy as np
from supervision.config import CLASS_NAME_DATA_FIELD, ORIENTED_BOX_COORDINATES
from supervision.detection.utils import (
box_non_max_suppression,
calculate_masks_centroids,
extract_ultralytics_masks,
get_data_item,
is_data_equal,
mask_non_max_suppression,
merge_data,
non_max_suppression,
process_roboflow_result,
validate_detections_fields,
xywh_to_xyxy,
@@ -1001,7 +1002,8 @@ class Detections:
self, threshold: float = 0.5, class_agnostic: bool = False
) -> Detections:
"""
Perform non-maximum suppression on the current set of object detections.
Performs non-max suppression on detection set. If the detections result
from a segmentation model, the IoU mask is applied. Otherwise, box IoU is used.
Args:
threshold (float, optional): The intersection-over-union threshold
@@ -1028,18 +1030,26 @@ class Detections:
if class_agnostic:
predictions = np.hstack((self.xyxy, self.confidence.reshape(-1, 1)))
indices = non_max_suppression(
else:
assert self.class_id is not None, (
"Detections class_id must be given for NMS to be executed. If you"
" intended to perform class agnostic NMS set class_agnostic=True."
)
predictions = np.hstack(
(
self.xyxy,
self.confidence.reshape(-1, 1),
self.class_id.reshape(-1, 1),
)
)
if self.mask is not None:
indices = mask_non_max_suppression(
predictions=predictions, masks=self.mask, iou_threshold=threshold
)
else:
indices = box_non_max_suppression(
predictions=predictions, iou_threshold=threshold
)
return self[indices]
assert self.class_id is not None, (
"Detections class_id must be given for NMS to be executed. If you intended"
" to perform class agnostic NMS set class_agnostic=True."
)
predictions = np.hstack(
(self.xyxy, self.confidence.reshape(-1, 1), self.class_id.reshape(-1, 1))
)
indices = non_max_suppression(predictions=predictions, iou_threshold=threshold)
return self[indices]
+113 -1
View File
@@ -59,7 +59,119 @@ def box_iou_batch(boxes_true: np.ndarray, boxes_detection: np.ndarray) -> np.nda
return area_inter / (area_true[:, None] + area_detection - area_inter)
def non_max_suppression(
def mask_iou_batch(masks_true: np.ndarray, masks_detection: np.ndarray) -> np.ndarray:
"""
Compute Intersection over Union (IoU) of two sets of masks -
`masks_true` and `masks_detection`.
Args:
masks_true (np.ndarray): 3D `np.ndarray` representing ground-truth masks.
masks_detection (np.ndarray): 3D `np.ndarray` representing detection masks.
Returns:
np.ndarray: Pairwise IoU of masks from `masks_true` and `masks_detection`.
"""
intersection_area = np.logical_and(masks_true[:, None], masks_detection).sum(
axis=(2, 3)
)
masks_true_area = masks_true.sum(axis=(1, 2))
masks_detection_area = masks_detection.sum(axis=(1, 2))
union_area = masks_true_area[:, None] + masks_detection_area - intersection_area
return np.divide(
intersection_area,
union_area,
out=np.zeros_like(intersection_area, dtype=float),
where=union_area != 0,
)
def resize_masks(masks: np.ndarray, max_dimension: int = 640) -> np.ndarray:
"""
Resize all masks in the array to have a maximum dimension of max_dimension,
maintaining aspect ratio.
Args:
masks (np.ndarray): 3D array of binary masks with shape (N, H, W).
max_dimension (int): The maximum dimension for the resized masks.
Returns:
np.ndarray: Array of resized masks.
"""
max_height = np.max(masks.shape[1])
max_width = np.max(masks.shape[2])
scale = min(max_dimension / max_height, max_dimension / max_width)
new_height = int(scale * max_height)
new_width = int(scale * max_width)
x = np.linspace(0, max_width - 1, new_width).astype(int)
y = np.linspace(0, max_height - 1, new_height).astype(int)
xv, yv = np.meshgrid(x, y)
resized_masks = masks[:, yv, xv]
resized_masks = resized_masks.reshape(masks.shape[0], new_height, new_width)
return resized_masks
def mask_non_max_suppression(
predictions: np.ndarray,
masks: np.ndarray,
iou_threshold: float = 0.5,
mask_dimension: int = 640,
) -> np.ndarray:
"""
Perform Non-Maximum Suppression (NMS) on segmentation predictions.
Args:
predictions (np.ndarray): A 2D array of object detection predictions in
the format of `(x_min, y_min, x_max, y_max, score)`
or `(x_min, y_min, x_max, y_max, score, class)`. Shape: `(N, 5)` or
`(N, 6)`, where N is the number of predictions.
masks (np.ndarray): A 3D array of binary masks corresponding to the predictions.
Shape: `(N, H, W)`, where N is the number of predictions, and H, W are the
dimensions of each mask.
iou_threshold (float, optional): The intersection-over-union threshold
to use for non-maximum suppression.
mask_dimension (int, optional): The dimension to which the masks should be
resized before computing IOU values. Defaults to 640.
Returns:
np.ndarray: A boolean array indicating which predictions to keep after
non-maximum suppression.
Raises:
AssertionError: If `iou_threshold` is not within the closed
range from `0` to `1`.
"""
assert 0 <= iou_threshold <= 1, (
"Value of `iou_threshold` must be in the closed range from 0 to 1, "
f"{iou_threshold} given."
)
rows, columns = predictions.shape
if columns == 5:
predictions = np.c_[predictions, np.zeros(rows)]
sort_index = predictions[:, 4].argsort()[::-1]
predictions = predictions[sort_index]
masks = masks[sort_index]
masks_resized = resize_masks(masks, mask_dimension)
ious = mask_iou_batch(masks_resized, masks_resized)
categories = predictions[:, 5]
keep = np.ones(rows, dtype=bool)
for i in range(rows):
if keep[i]:
condition = (ious[i] > iou_threshold) & (categories[i] == categories)
keep[i + 1 :] = np.where(condition[i + 1 :], False, keep[i + 1 :])
return keep[sort_index.argsort()]
def box_non_max_suppression(
predictions: np.ndarray, iou_threshold: float = 0.5
) -> np.ndarray:
"""
+210 -3
View File
@@ -6,13 +6,14 @@ import pytest
from supervision.config import CLASS_NAME_DATA_FIELD
from supervision.detection.utils import (
box_non_max_suppression,
calculate_masks_centroids,
clip_boxes,
filter_polygons_by_area,
get_data_item,
mask_non_max_suppression,
merge_data,
move_boxes,
non_max_suppression,
process_roboflow_result,
scale_boxes,
)
@@ -113,19 +114,225 @@ TEST_MASK[:, 300:351, 200:251] = True
), # three boxes with different category
],
)
def test_non_max_suppression(
def test_box_non_max_suppression(
predictions: np.ndarray,
iou_threshold: float,
expected_result: Optional[np.ndarray],
exception: Exception,
) -> None:
with exception:
result = non_max_suppression(
result = box_non_max_suppression(
predictions=predictions, iou_threshold=iou_threshold
)
assert np.array_equal(result, expected_result)
@pytest.mark.parametrize(
"predictions, masks, iou_threshold, expected_result, exception",
[
(
np.empty((0, 6)),
np.empty((0, 5, 5)),
0.5,
np.array([]),
DoesNotRaise(),
), # empty predictions and masks
(
np.array([[0, 0, 0, 0, 0.8]]),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, False, False, False, False],
]
]
),
0.5,
np.array([True]),
DoesNotRaise(),
), # single mask with no category
(
np.array([[0, 0, 0, 0, 0.8, 0]]),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, False, False, False, False],
]
]
),
0.5,
np.array([True]),
DoesNotRaise(),
), # single mask with category
(
np.array([[0, 0, 0, 0, 0.8], [0, 0, 0, 0, 0.9]]),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, True, True],
[False, False, False, True, True],
[False, False, False, False, False],
],
]
),
0.5,
np.array([True, True]),
DoesNotRaise(),
), # two masks non-overlapping with no category
(
np.array([[0, 0, 0, 0, 0.8], [0, 0, 0, 0, 0.9]]),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, False, False, False],
],
]
),
0.4,
np.array([False, True]),
DoesNotRaise(),
), # two masks partially overlapping with no category
(
np.array([[0, 0, 0, 0, 0.8, 0], [0, 0, 0, 0, 0.9, 1]]),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, False, False, False],
],
]
),
0.5,
np.array([True, True]),
DoesNotRaise(),
), # two masks partially overlapping with different category
(
np.array(
[
[0, 0, 0, 0, 0.8],
[0, 0, 0, 0, 0.85],
[0, 0, 0, 0, 0.9],
]
),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, False, False, True, True],
[False, False, False, True, True],
[False, False, False, False, False],
[False, False, False, False, False],
],
]
),
0.5,
np.array([False, True, True]),
DoesNotRaise(),
), # three masks with no category
(
np.array(
[
[0, 0, 0, 0, 0.8, 0],
[0, 0, 0, 0, 0.85, 1],
[0, 0, 0, 0, 0.9, 2],
]
),
np.array(
[
[
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, False, False, False, False],
],
[
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, True, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
],
]
),
0.5,
np.array([True, True, True]),
DoesNotRaise(),
), # three masks with different category
],
)
def test_mask_non_max_suppression(
predictions: np.ndarray,
masks: np.ndarray,
iou_threshold: float,
expected_result: Optional[np.ndarray],
exception: Exception,
) -> None:
with exception:
result = mask_non_max_suppression(
predictions=predictions, masks=masks, iou_threshold=iou_threshold
)
assert np.array_equal(result, expected_result)
@pytest.mark.parametrize(
"xyxy, resolution_wh, expected_result",
[