Compare commits

...
836 Commits
Author SHA1 Message Date
Piotr Skalski 53f4cde18d Merge pull request #764 from roboflow/develop
`supervision-0.18.0` release
2024-01-25 10:33:16 +01:00
Piotr Skalski 181724e2d3 Merge pull request #775 from roboflow/feature/supervision-0-18-0-changelog
`supervision-0.18.0` change log update
2024-01-25 10:31:17 +01:00
pre-commit-ci[bot] 205b2d200a fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-25 09:29:43 +00:00
SkalskiP 3dcb330822 - version bump from 0.18.0rc4 to 0.18.0
- `supervision-0.18.0` release changelog update
- minot docs changes
2024-01-25 10:27:22 +01:00
SkalskiP 6fa4f25250 bump version from 0.18.0rc3 to 0.18.0rc4 2024-01-24 18:10:56 +01:00
Piotr Skalski 35d5738622 Merge pull request #770 from roboflow/yolov8-obb
feat: ✨ yolov8-obb support and OrientedBoxAnnotator added for obb
2024-01-24 17:50:41 +01:00
pre-commit-ci[bot] 9d56d8a9fe fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-24 16:47:55 +00:00
SkalskiP c7d7e8b71e Merge remote-tracking branch 'origin/yolov8-obb' into yolov8-obb
# Conflicts:
#	docs/annotators.md
2024-01-24 17:47:41 +01:00
SkalskiP 6565fae1c2 final docs updates 2024-01-24 17:47:11 +01:00
Onuralp SEZER a5bef3b15e docs: 📝 >>>/... removed from obb docs and code example
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 19:31:46 +03:00
SkalskiP 164b9bedce Merge branch 'develop' into yolov8-obb 2024-01-24 16:49:00 +01:00
Piotr Skalski aabe60be6a Merge pull request #774 from roboflow/docs-emojis-fix
fix(docs): 🐞 emoji extension added for show emojis properly
2024-01-24 16:42:19 +01:00
Piotr Skalski 533a8a1aa3 Merge pull request #773 from roboflow/readme-example-docs
docs: 📝 readme >>>/... removed
2024-01-24 16:33:43 +01:00
Onuralp SEZER c7790fdf56 fix(docs): 🐞 emoji extension added for show emojis properly
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 17:53:56 +03:00
Onuralp SEZER dd53cd06b9 docs: 📝 readme >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 17:43:10 +03:00
Onuralp SEZER 24593b64d5 Removed '>>>' and '...' from docs - Merge PR #761 from RaghavvGupta/improved-code-usability
Removed '>>>' and '...' from examples and docs and improved some indentation.
2024-01-24 17:21:00 +03:00
Piotr Skalski 80b7eecfaf Merge pull request #696 from roboflow/prediction-smoothing
Add Prediction Smoothing
2024-01-24 15:13:13 +01:00
SkalskiP 6b063736d9 Merge remote-tracking branch 'origin/prediction-smoothing' into prediction-smoothing 2024-01-24 15:11:50 +01:00
SkalskiP 7b0d5e729e ready for merge 2024-01-24 15:09:47 +01:00
pre-commit-ci[bot] 7916d6a6a4 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-24 14:07:46 +00:00
SkalskiP 79560945f5 ready for merge 2024-01-24 15:07:32 +01:00
Onuralp SEZER d4e0d8d46d docs: 📝 supervision/annotators/core.py PercentageBarAnnotator >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 15:41:18 +03:00
Onuralp SEZER 5a89e2170f Merge remote-tracking branch 'mainland/develop' into improved-code-usability 2024-01-24 15:39:07 +03:00
Onuralp SEZER ab5a86596f docs: 📝 supervision downloader classfication draw geometry and utils >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 15:26:43 +03:00
Onuralp SEZER 12b42f80de docs: 📝 supervision/utils/notebook.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 15:17:49 +03:00
Onuralp SEZER 8a5cd1bc3e docs: 📝 supervision/utils/video.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 15:17:29 +03:00
Onuralp SEZER e29e960c5f docs: 📝 supervision/metrics/detection.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 15:14:18 +03:00
pre-commit-ci[bot] f6e5b6dc54 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-24 12:06:21 +00:00
SkalskiP e2751368d5 improvements 2024-01-24 13:06:07 +01:00
Onuralp SEZER 955a6d67fb docs: 📝 supervision/tracker/byte_tracker/core.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 13:13:56 +03:00
Onuralp SEZER 833edc95ad docs: 📝 supervision/detection/utils.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 13:10:48 +03:00
Onuralp SEZER 4df21ded6a docs: 📝 supervision/detection/annotate.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 13:03:34 +03:00
Onuralp SEZER f03be21a9f docs: 📝 supervision/dataset/core.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 13:01:55 +03:00
Onuralp SEZER 2d1aa3b996 docs: 📝 supervision/detection/tools/inference_slicer.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 12:52:34 +03:00
Onuralp SEZER 7af914bf56 docs: 📝 supervision/annotators/core.py docs/annotators.md >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 12:50:23 +03:00
Onuralp SEZER 8872151d0c docs: 📝 core/detection/core.py >>>/... removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 12:28:45 +03:00
raghav d961aa9eb4 docs: example image = ... reverted and added annotators.md 2024-01-24 12:05:57 +03:00
raghav 845c9cc2c2 docs: '>>>' and '...' are removed and indentation improvements 2024-01-24 12:05:48 +03:00
Piotr Skalski 4667e02d79 Merge pull request #772 from roboflow/mkdocs-matplotlib-updates
build(deps): 📦 mkdocs-material and matplotlib update for security
2024-01-24 09:07:43 +01:00
Onuralp SEZER 047672d458 build(deps): 📦 mkdocs-material and matplotlib update for security
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-24 10:51:41 +03:00
Piotr Skalski 2622144660 Merge pull request #771 from roboflow/removal-pillow-reqs
build(deps): 📦 package pillow removed
2024-01-23 20:15:31 +01:00
Onuralp SEZER fb0500c394 build(deps): 📦 package pillow removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-23 21:19:01 +03:00
Onuralp SEZER 10f3b73e79 docs: 📝 OrientedBox Annotator docs added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-23 21:07:09 +03:00
Onuralp SEZER 564f979977 Merge branch 'develop' into yolov8-obb 2024-01-23 20:52:07 +03:00
Onuralp SEZER 64302f450c feat: ✨ yolov8-obb support and OrientedBoxAnnotator added for obb
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-23 20:18:47 +03:00
SkalskiP 239ea649c0 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	supervision/annotators/core.py
2024-01-23 18:10:18 +01:00
James Gallagher 626636cfa7 update tracking logic 2024-01-23 17:10:02 +00:00
SkalskiP 6b14cc9572 bump version from 0.18.0rc2 to 0.18.0rc3 2024-01-23 18:09:24 +01:00
SkalskiP 294a476977 bump version from 0.18.0rc2 to 0.18.0rc3 2024-01-23 18:07:25 +01:00
Piotr Skalski 4fedb87f97 Merge pull request #769 from roboflow/feature/color_and_color_palette_updates
`feature/color_and_color_palette_updates`
2024-01-23 17:21:15 +01:00
pre-commit-ci[bot] a1b2297e9f fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-23 16:14:04 +00:00
SkalskiP c064c1fc98 final tests 2024-01-23 17:13:51 +01:00
pre-commit-ci[bot] 0f3359c15f fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-23 15:57:57 +00:00
SkalskiP a9987dbc83 test @classproperty decorator 2024-01-23 16:57:10 +01:00
SkalskiP b14a035ede final changes 2024-01-23 16:45:15 +01:00
SkalskiP 295e8b725b added from_matplotlib method 2024-01-23 16:34:22 +01:00
pre-commit-ci[bot] fa8a9cb5ac fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-23 15:25:02 +00:00
SkalskiP 66245dd0df added documentation and examples 2024-01-23 16:24:15 +01:00
SkalskiP 2d0a3f9d79 working on optimal syntax 2024-01-23 15:42:27 +01:00
pre-commit-ci[bot] 7b2c09c0ab fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-23 14:19:08 +00:00
SkalskiP d314bf0364 initial tests 2024-01-23 14:58:06 +01:00
James Gallagher 21791c8522 remove idle trackers 2024-01-23 13:38:15 +00:00
James Gallagher 24ca25ef94 fix formatting 2024-01-23 13:28:00 +00:00
James 09d771c139 Merge branch 'develop' into prediction-smoothing 2024-01-23 12:59:28 +00:00
James Gallagher 6efd51dfb1 respond to feedback 2024-01-23 12:57:36 +00:00
James Gallagher c299a929c5 respond to feedback 2024-01-23 12:57:31 +00:00
Onuralp SEZER f5f068bffd Merge pull request #720 from xaristeidou/develop
Add `sv.PercentageBarAnnotator()` for confidence level bar annotation in specified position
2024-01-23 14:39:33 +03:00
SkalskiP fc22a9ccd9 update visualization path 2024-01-23 12:32:18 +01:00
SkalskiP 45fe3c1c0f small bug fix 2024-01-23 12:13:08 +01:00
pre-commit-ci[bot] 027b60837a fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-23 10:56:11 +00:00
SkalskiP fa569cb235 ready for tests 2024-01-23 11:54:40 +01:00
Onuralp SEZER 2bc58e7938 feat(core.py): 🚀 Allow custom NumPy array for custom_values in PercentageBarAnnotator
fix(core.py): 🐞 Treat CENTER_OF_MASS the same as CENTER in PercentageBarAnnotator
refactor(core.py): Move border mapping logic to separate method in PercentageBarAnnotator

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-23 04:34:59 +03:00
Onuralp SEZER 6f87069080 docs: 📝 PercentageBar Annotator image added into core.py
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-22 22:13:35 +03:00
Onuralp SEZER c0c541d121 docs: 📝 PercentageBar Annotator docs and usage added.
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-22 22:13:20 +03:00
pre-commit-ci[bot] 08173899a9 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-22 18:51:36 +00:00
Onuralp SEZER 6e9bfc9a05 chore: 🧹 folder attiributes ignored
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-22 21:51:03 +03:00
Onuralp SEZER 65eda0b80c build(docs): 👷 mkdocs-material with imaging dep added for development
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-22 21:46:38 +03:00
Christoforos Aristeidou 740076d961 pre-commit spacing 2024-01-22 21:42:22 +03:00
Christoforos Aristeidou f3cb8e9d27 reformed fill of confidence rectangle, changed border attributes 2024-01-22 21:42:22 +03:00
Christoforos Aristeidou 846b337155 changed if else statements to dictionary mapping 2024-01-22 21:42:21 +03:00
Christoforos Aristeidou ce19f917e9 changed border thickness percentage, extract confidence level 2024-01-22 21:42:21 +03:00
Christoforos Aristeidou c70ee87897 deleted unused coordinates and changed type of anchor coords 2024-01-22 21:42:21 +03:00
Christoforos Aristeidou 786942ba7e changed default value for height 2024-01-22 21:42:21 +03:00
Christoforos Aristeidou 5ed3430b16 corrected border color, added rectangle for percentage 2024-01-22 21:42:21 +03:00
Christoforos Aristeidou 39ef293926 added if else statements for different anchors 2024-01-22 21:42:21 +03:00
Christoforos Aristeidou a59d84549f added anchor xy coordinates 2024-01-22 21:42:20 +03:00
Christoforos Aristeidou f94c0a4930 arguments description update 2024-01-22 21:42:20 +03:00
Christoforos Aristeidou ae7360b5e0 added new attributes of class 2024-01-22 21:42:20 +03:00
Christoforos Aristeidou e809e424e6 added PercentageBarAnnotator() to __init__ of package 2024-01-22 21:42:20 +03:00
Christoforos Aristeidou b1dbeaf9c4 changed class name and description 2024-01-22 21:42:20 +03:00
Christoforos Aristeidou fbcc211079 added boundingboxannotator class to re-write class 2024-01-22 21:42:19 +03:00
Onuralp SEZER 6b7ccfccd9 Merge pull request #763 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2024-01-22 21:16:52 +03:00
Onuralp SEZER 5677b4b5e3 Merge pull request #762 from roboflow/dependabot/pip/ruff-0.1.14
⬆️ Bump ruff from 0.1.13 to 0.1.14
2024-01-22 21:16:37 +03:00
pre-commit-ci[bot] c323ecba8a chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.13 → v0.1.14](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.13...v0.1.14)
2024-01-22 17:34:15 +00:00
dependabot[bot] 995f170e30 ⬆️ Bump ruff from 0.1.13 to 0.1.14
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.13 to 0.1.14.
- [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.1.13...v0.1.14)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 00:57:36 +00:00
Onuralp SEZER decbbb62ad Merge pull request #759 from roboflow/dependabot/pip/jupyterlab-4.0.11
⬆️ Bump jupyterlab from 4.0.10 to 4.0.11
2024-01-20 22:36:01 +03:00
Onuralp SEZER 7d3c2114dd Merge pull request #760 from roboflow/dependabot/pip/notebook-7.0.7
⬆️ Bump notebook from 7.0.6 to 7.0.7
2024-01-20 22:35:45 +03:00
dependabot[bot] b008aadd41 ⬆️ Bump notebook from 7.0.6 to 7.0.7
Bumps [notebook](https://github.com/jupyter/notebook) from 7.0.6 to 7.0.7.
- [Release notes](https://github.com/jupyter/notebook/releases)
- [Changelog](https://github.com/jupyter/notebook/blob/@jupyter-notebook/tree@7.0.7/CHANGELOG.md)
- [Commits](https://github.com/jupyter/notebook/compare/@jupyter-notebook/tree@7.0.6...@jupyter-notebook/tree@7.0.7)

---
updated-dependencies:
- dependency-name: notebook
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-19 20:45:54 +00:00
dependabot[bot] cca120915e ⬆️ Bump jupyterlab from 4.0.10 to 4.0.11
Bumps [jupyterlab](https://github.com/jupyterlab/jupyterlab) from 4.0.10 to 4.0.11.
- [Release notes](https://github.com/jupyterlab/jupyterlab/releases)
- [Changelog](https://github.com/jupyterlab/jupyterlab/blob/@jupyterlab/lsp@4.0.11/CHANGELOG.md)
- [Commits](https://github.com/jupyterlab/jupyterlab/compare/@jupyterlab/lsp@4.0.10...@jupyterlab/lsp@4.0.11)

---
updated-dependencies:
- dependency-name: jupyterlab
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-19 20:39:08 +00:00
Piotr Skalski 4e4fad9d04 Merge pull request #756 from roboflow/q1-2024/color-properties
feat(color.py): ✨ add color constants/properties
2024-01-19 09:04:50 +01:00
pre-commit-ci[bot] 38bdeff171 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-18 22:43:26 +00:00
Onuralp SEZER 6fee626828 refactor(Color): 🎨 Deprecate color methods in favor of color properties
Deprecated the `white`, `black`, `red`, `green`, and `blue` methods in
the `Color` class.
Users should now use the `WHITE`, `BLACK`, `RED`, `GREEN`, and `BLUE`
properties instead. This change improves the API and makes it more consistent.

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-19 01:41:31 +03:00
Onuralp SEZER bb4d741aff feat(color.py): ✨ add color constants
This commit adds the WHITE, BLACK, RED, GREEN, and BLUE color constants
to the Color class in color.py. These constants represent
the corresponding colors in the RGB color space.

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-19 00:42:59 +03:00
Piotr Skalski d503e3aa50 Merge pull request #750 from roboflow/opencv-version
fix: ✨ bump opencv version and remove upper limit
2024-01-18 21:42:04 +01:00
Onuralp SEZER 3b13fc41a7 fix: ✨ bump opencv version and remove upper limit
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-18 23:38:06 +03:00
Piotr Skalski 9e6abc0fff Merge pull request #747 from roboflow/scipy-security
fix(security): 🔐 bump scipy version for memory leak vulnerability
2024-01-18 21:26:21 +01:00
Onuralp SEZER 3e48708910 fix(security): 🔐 bump scipy version for memory leak vulnerability
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-18 22:56:59 +03:00
Onuralp SEZER 215741fd83 Merge pull request #742 from roboflow/dependabot/pip/tox-4.12.1
⬆️ Bump tox from 4.12.0 to 4.12.1
2024-01-18 22:34:41 +03:00
Onuralp SEZER c2a5583aa2 Merge pull request #745 from roboflow/dependabot/pip/jupyter-lsp-2.2.2
⬆️ Bump jupyter-lsp from 2.2.1 to 2.2.2
2024-01-18 22:31:46 +03:00
Piotr Skalski c04edbcf85 Merge pull request #735 from revtheundead/add-center-point-crossed-condition-to-line-counter
Added an option to count detection upon the center point of the bounding box crossing the line counter
2024-01-18 17:52:13 +01:00
pre-commit-ci[bot] f768347d26 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-18 16:36:22 +00:00
dependabot[bot] ffc8c16993 ⬆️ Bump jupyter-lsp from 2.2.1 to 2.2.2
Bumps [jupyter-lsp](https://github.com/jupyter-lsp/jupyterlab-lsp) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/jupyter-lsp/jupyterlab-lsp/releases)
- [Changelog](https://github.com/jupyter-lsp/jupyterlab-lsp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jupyter-lsp/jupyterlab-lsp/commits)

---
updated-dependencies:
- dependency-name: jupyter-lsp
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-18 16:36:12 +00:00
pre-commit-ci[bot] 6128576ea1 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-18 16:06:10 +00:00
Piotr Skalski cda5016a5a Merge branch 'develop' into add-center-point-crossed-condition-to-line-counter 2024-01-18 17:06:01 +01:00
SkalskiP f8ee3a4290 ready for end-to-end tests. 2024-01-18 16:43:17 +01:00
SkalskiP 5f04836917 calculate_region_of_interest_limits and is_point_in_limits methods added. 2024-01-18 13:36:47 +01:00
SkalskiP 616fc96ca8 Adding ability to calculate vector magnitude. 2024-01-18 12:46:09 +01:00
rev dca7fb43e5 Revert "Fixed cross_product() funtion test"
This reverts commit 353865e017.
2024-01-18 13:50:03 +03:00
rev ec7baf3360 Revert "Implemented cross_product() with numpy"
This reverts commit 9fb97e3c79.
2024-01-18 13:49:54 +03:00
rev 9fb97e3c79 Implemented cross_product() with numpy 2024-01-18 13:45:30 +03:00
Piotr Skalski 536e0d86a8 Merge pull request #733 from roboflow/fix/speed-estimation-issue-when-detections-empty
`fix/speed-estimation-issue-when-detections-empty`
2024-01-18 11:30:04 +01:00
SkalskiP 3a608eeb93 Merge remote-tracking branch 'origin/add-center-point-crossed-condition-to-line-counter' into add-center-point-crossed-condition-to-line-counter 2024-01-18 11:29:18 +01:00
SkalskiP 008b0bd984 Formatting updates. 2024-01-18 11:29:01 +01:00
rev 353865e017 Fixed cross_product() funtion test 2024-01-18 13:26:01 +03:00
SkalskiP da4ee62298 Fixing cross_product tests. 2024-01-18 11:18:18 +01:00
rev ae758a655d Fixed the is_in_line_range() function logic and fixed a minor bug with finding anchors 2024-01-18 12:35:00 +03:00
pre-commit-ci[bot] e38256f316 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-18 00:46:10 +00:00
dependabot[bot] 713bacae08 ⬆️ Bump tox from 4.12.0 to 4.12.1
Bumps [tox](https://github.com/tox-dev/tox) from 4.12.0 to 4.12.1.
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.12.0...4.12.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-18 00:46:02 +00:00
rev 2367fcac82 Resolved merge conflict 2024-01-18 01:41:25 +03:00
rev 1f640980ad Increased line counter flexibility and replaced vector cross product function 2024-01-18 01:21:45 +03:00
Piotr Skalski 64661a3e4a Update built with supervision section in README.md 2024-01-17 15:54:12 +01:00
Piotr Skalski 1c414bd70f Update speed estimation example tutorial README.md 2024-01-17 15:52:41 +01:00
Piotr Skalski e32b05a636 Update speed estimation example tutorial README.md 2024-01-17 15:38:19 +01:00
Piotr Skalski 688cf14f2a Merge pull request #739 from roboflow/feature/add-comments-system-powered-by-github-discussions
`feature/add-comments-system-powered-by-github-discussions`
2024-01-17 12:16:21 +01:00
pre-commit-ci[bot] e3529436e1 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-17 11:14:03 +00:00
SkalskiP 99d1b6d130 ready for review 2024-01-17 12:11:31 +01:00
SkalskiP 2ba6a22d69 bump version from 0.18.0rc1 to 0.18.0rc2 2024-01-17 09:12:53 +01:00
Piotr Skalski 3de2efea12 Merge pull request #737 from roboflow/fix/line-zone-trigger-returns-value-error
`fix/line-zone-trigger-returns-value-error`
2024-01-17 09:12:10 +01:00
pre-commit-ci[bot] f7145aa6aa fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-17 08:06:37 +00:00
SkalskiP b12d73a883 ready for review 2024-01-17 09:01:17 +01:00
pre-commit-ci[bot] 47eed7257c fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-16 23:09:46 +00:00
rev 602676bd9c Change cross_product() return type from int to float 2024-01-17 02:06:36 +03:00
rev 0e1f422a75 Added an option to count detection upon the center point of the bounding box crossing the line counter.
Added an option to LineCounter class specifying the condition which determines whether a detection has crossed the line counter or not.

Additionally made it so that the line counters check whether if the corners (or optionally the center point) of a detection's bounding box are in the line counter's coordinate ranges. This way, line counters count only the detections that have precisely crossed the bounds that are drawn without failing and counting targets that have crossed invisible extensions of the lines.
2024-01-17 01:24:49 +03:00
Onuralp SEZER 3b531249bc Merge pull request #731 from roboflow/dependabot/pip/mkdocs-material-9.5.4
⬆️ Bump mkdocs-material from 9.5.3 to 9.5.4
2024-01-16 20:01:05 +03:00
pre-commit-ci[bot] 4d8f15f295 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-16 16:55:57 +00:00
SkalskiP c78354203d ready for review 2024-01-16 17:51:56 +01:00
Piotr Skalski 624a2e4c10 Update tutorials section in README.md 2024-01-16 14:59:40 +01:00
dependabot[bot] 4c063acd2b ⬆️ Bump mkdocs-material from 9.5.3 to 9.5.4
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.5.3 to 9.5.4.
- [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.3...9.5.4)

---
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-01-16 00:36:23 +00:00
Onuralp SEZER 0b805b7a04 Merge pull request #730 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2024-01-15 23:23:42 +03:00
pre-commit-ci[bot] a8081bec05 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.11 → v0.1.13](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.11...v0.1.13)
2024-01-15 17:30:17 +00:00
Onuralp SEZER 68df3604ea Merge pull request #727 from roboflow/dependabot/pip/tox-4.12.0
⬆️ Bump tox from 4.11.4 to 4.12.0
2024-01-15 04:23:11 +03:00
Onuralp SEZER 3224032542 Merge pull request #726 from roboflow/dependabot/pip/ruff-0.1.13
⬆️ Bump ruff from 0.1.12 to 0.1.13
2024-01-15 04:22:58 +03:00
dependabot[bot] 1005de429c ⬆️ Bump tox from 4.11.4 to 4.12.0
Bumps [tox](https://github.com/tox-dev/tox) from 4.11.4 to 4.12.0.
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.11.4...4.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 00:48:05 +00:00
dependabot[bot] 1f1edfc8f8 ⬆️ Bump ruff from 0.1.12 to 0.1.13
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.12 to 0.1.13.
- [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.1.12...v0.1.13)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 00:41:57 +00:00
Onuralp SEZER 338d62b2cb Merge pull request #721 from roboflow/dependabot/pip/ruff-0.1.12
⬆️ Bump ruff from 0.1.11 to 0.1.12
2024-01-13 03:14:32 +03:00
dependabot[bot] 17f7949b96 ⬆️ Bump ruff from 0.1.11 to 0.1.12
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.11 to 0.1.12.
- [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.1.11...v0.1.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-12 00:42:35 +00:00
Onuralp SEZER 5ceb61a185 Merge pull request #719 from roboflow/dependabot/pip/jinja2-3.1.3
⬆️ Bump jinja2 from 3.1.2 to 3.1.3
2024-01-12 00:31:21 +03:00
dependabot[bot] 27d6832507 ⬆️ Bump jinja2 from 3.1.2 to 3.1.3
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.2...3.1.3)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-11 21:12:58 +00:00
James 8acc0a9ed8 Merge pull request #684 from roboflow/py38req
ci: 👷 close dependabot warning and PR requests for min version(py38)
2024-01-11 13:18:52 +00:00
Onuralp SEZER 97d9472f42 Add sv.RoundBoxAnnotator #702 from xaristeidou/develop
Add `sv.RoundBoxAnnotator` which annotates bounding box with round edges
2024-01-10 14:43:48 +03:00
Onuralp SEZER f3fa12d169 feat(rename): ✨ RoundBoundingBoxAnnotator to RoundBoxAnnotator
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-10 14:41:12 +03:00
Piotr Skalski 9b5bba1422 Merge pull request #714 from roboflow/example/speed_estimation
example/speed_estimation 🚗 💨💨💨
2024-01-10 12:10:52 +01:00
Onuralp SEZER a337ee591a feat: ✨ supervison downloader added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-09 05:15:28 +03:00
Onuralp SEZER a1da604798 Merge pull request #716 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2024-01-08 21:27:35 +03:00
pre-commit-ci[bot] 1d4c3f3a68 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.9 → v0.1.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.9...v0.1.11)
2024-01-08 17:42:51 +00:00
Piotr Skalski a72ad42628 Update README.md 2024-01-08 14:02:27 +01:00
pre-commit-ci[bot] be5748c086 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-08 12:57:53 +00:00
SkalskiP 9e05a545c7 Merge remote-tracking branch 'origin/example/speed_estimation' into example/speed_estimation
# Conflicts:
#	examples/speed_estimation/README.md
2024-01-08 13:57:37 +01:00
SkalskiP f0142344ae update note in speed estimation emo README.md 2024-01-08 13:57:17 +01:00
pre-commit-ci[bot] d596d10b3f fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-08 12:52:34 +00:00
SkalskiP 86134993c8 Merge remote-tracking branch 'origin/example/speed_estimation' into example/speed_estimation 2024-01-08 13:52:19 +01:00
SkalskiP 8bab49157d working version of inference_example.py 2024-01-08 13:52:09 +01:00
SkalskiP bcbd25988d 👊 bump version from 0.17.1 to 0.18.0rc1 2024-01-08 13:31:11 +01:00
SkalskiP 24e995933e 👊 bump version from 0.17.1 to 0.18.0rc1 2024-01-08 13:12:41 +01:00
pre-commit-ci[bot] 4ae9131f0a fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-08 12:03:31 +00:00
SkalskiP 69894c82af initial version of inference_example.py script 2024-01-08 13:01:08 +01:00
SkalskiP e009402934 yolo_nas_example.py script is ready 2024-01-08 12:26:43 +01:00
SkalskiP 351ef464d9 initial version of yolo_nas_example.py script 2024-01-08 12:04:29 +01:00
SkalskiP 949e326559 updated README.md and ultralytics_example.py 2024-01-08 08:55:28 +01:00
SkalskiP 0a7e116d7f added script.sh and updated README.md 2024-01-08 08:34:55 +01:00
SkalskiP 5ce65a2fd5 current version 2024-01-08 08:11:40 +01:00
Onuralp SEZER 73ae555e10 docs: 📝 RoundBoundingBox documentations roundness fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-06 03:33:10 +03:00
Onuralp SEZER 98c0b8c2a5 Merge branch 'develop' into develop 2024-01-05 23:01:13 +03:00
Onuralp SEZER 7b7a734f2c docs: 📝 RoundBoundingBox documentations and small change on code section
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2024-01-05 22:59:29 +03:00
Onuralp SEZER e9ba3ca918 Merge pull request #712 from roboflow/dependabot/pip/mkdocs-material-9.5.3
⬆️ Bump mkdocs-material from 9.5.2 to 9.5.3
2024-01-05 20:40:48 +03:00
Onuralp SEZER 4c16af5544 Merge pull request #713 from roboflow/dependabot/pip/mypy-1.8.0
⬆️ Bump mypy from 1.7.1 to 1.8.0
2024-01-05 20:40:30 +03:00
Onuralp SEZER 893dbe0579 Merge pull request #711 from roboflow/dependabot/pip/pytest-7.4.4
⬆️ Bump pytest from 7.4.3 to 7.4.4
2024-01-05 20:40:17 +03:00
SkalskiP 3e6c1799ef current version 2024-01-05 16:51:27 +01:00
dependabot[bot] e53c804217 ⬆️ Bump mypy from 1.7.1 to 1.8.0
Bumps [mypy](https://github.com/python/mypy) from 1.7.1 to 1.8.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.7.1...v1.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-05 00:26:59 +00:00
dependabot[bot] 6dcd947110 ⬆️ Bump mkdocs-material from 9.5.2 to 9.5.3
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.5.2 to 9.5.3.
- [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.2...9.5.3)

---
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-01-05 00:24:59 +00:00
dependabot[bot] 13fc3f76f8 ⬆️ Bump pytest from 7.4.3 to 7.4.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.3 to 7.4.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.4.3...7.4.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-05 00:22:11 +00:00
SkalskiP d83547ec80 initial working version 2024-01-04 23:38:47 +01:00
SkalskiP 7e8d44ac35 dropping idea of using lines to calculate speed 2024-01-04 22:35:59 +01:00
SkalskiP 2e9b2a1bcb detection, tracking and annotation added 2024-01-04 20:54:37 +01:00
SkalskiP 5df9730b3f 🚗💨💨💨 speed estimation example initial commit 2024-01-04 20:08:01 +01:00
Onuralp SEZER e1ef7aa849 Merge pull request #706 from roboflow/dependabot/pip/pillow-10.2.0
⬆️ Bump pillow from 10.1.0 to 10.2.0
2024-01-04 21:06:34 +03:00
Onuralp SEZER 77f17a3fde Merge pull request #707 from roboflow/dependabot/pip/ruff-0.1.11
⬆️ Bump ruff from 0.1.9 to 0.1.11
2024-01-04 21:06:20 +03:00
dependabot[bot] 030189e45f ⬆️ Bump ruff from 0.1.9 to 0.1.11
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.9 to 0.1.11.
- [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.1.9...v0.1.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-04 15:10:44 +00:00
Piotr Skalski 850614739b Merge pull request #677 from roboflow/feature/from-roboflow-base-model
Inference Examples and `from_roboflow` Update
2024-01-04 16:08:25 +01:00
pre-commit-ci[bot] de10b25dc4 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 15:07:05 +00:00
SkalskiP 7cde087ca6 update Track Objects docs page 2024-01-04 16:06:52 +01:00
SkalskiP 8348f5911e Merge remote-tracking branch 'origin/feature/from-roboflow-base-model' into feature/from-roboflow-base-model 2024-01-04 15:54:15 +01:00
SkalskiP be57c8872d make ruff happy 2024-01-04 15:52:40 +01:00
pre-commit-ci[bot] c963a2e85a fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 14:50:08 +00:00
SkalskiP bdaee3f1fc update Detect and annotate guide 2024-01-04 15:49:47 +01:00
pre-commit-ci[bot] c9be7527d6 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 14:22:39 +00:00
SkalskiP 7023bb9bf4 count people in zone example cleanup 2024-01-04 15:22:25 +01:00
pre-commit-ci[bot] a5c0949cd6 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 14:10:39 +00:00
SkalskiP 9862f40ab4 Merge remote-tracking branch 'origin/feature/from-roboflow-base-model' into feature/from-roboflow-base-model 2024-01-04 15:09:29 +01:00
SkalskiP 1ad9ee1e6a tracking example cleanup 2024-01-04 15:06:31 +01:00
pre-commit-ci[bot] 5b174ea7ec fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 13:58:44 +00:00
SkalskiP b5f9cdf90e Merge remote-tracking branch 'origin/feature/from-roboflow-base-model' into feature/from-roboflow-base-model
# Conflicts:
#	examples/traffic_analysis/README.md
2024-01-04 14:58:30 +01:00
SkalskiP 0acd408f29 traffic analysis example cleanup 2024-01-04 14:56:56 +01:00
pre-commit-ci[bot] 26829070f3 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 13:34:49 +00:00
SkalskiP 9c1f06046d traffic analysis example cleanup 2024-01-04 14:34:36 +01:00
SkalskiP ace32eecb6 improve Detections docstrings 2024-01-04 13:56:51 +01:00
pre-commit-ci[bot] 53803c77ca fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-04 12:30:25 +00:00
Piotr Skalski f86cd5114d Update README.md 2024-01-04 13:30:17 +01:00
Piotr Skalski 8a32a9ccb1 Update README.md example 2024-01-04 12:54:02 +01:00
SkalskiP 2e491a85c9 Merge branch 'develop' into feature/from-roboflow-base-model
# Conflicts:
#	poetry.lock
#	supervision/detection/core.py
2024-01-04 10:02:01 +01:00
Piotr Skalski 9e34cbb31c Merge pull request #708 from roboflow/feature/update-label-annotator-to-respect-class-name-detection-data-field
feature/update-label-annotator-to-respect-class-name-detection-data-field
2024-01-03 08:41:34 +01:00
SkalskiP 11cd92e4f3 update sv.LabelAnnotator to respect optional 'class_name' sv.Detections.data field 2024-01-03 08:19:14 +01:00
Piotr Skalski 1b386a45d5 Merge pull request #705 from roboflow/feature/extract-class-name-from-roboflow-result
feature/extract-class-name-from-roboflow-result
2024-01-03 07:56:59 +01:00
pre-commit-ci[bot] 80d1df7509 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-03 06:23:01 +00:00
SkalskiP f4d2f2a900 use CLASS_NAME_DATA_FIELD data constant over 'class_name' string 2024-01-03 07:22:48 +01:00
SkalskiP 0d10704370 improve from_roboflow docstring 2024-01-03 06:50:18 +01:00
dependabot[bot] 1001448f5c ⬆️ Bump pillow from 10.1.0 to 10.2.0
Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.1.0 to 10.2.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/10.1.0...10.2.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-03 00:37:50 +00:00
pre-commit-ci[bot] d35f1888f9 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-02 20:02:04 +00:00
SkalskiP 706ff0fd46 initial update of process_roboflow_result function 2024-01-02 21:00:17 +01:00
Piotr Skalski 8528a8a738 Merge pull request #700 from roboflow/feature/extend-detections-with-data-field-to-support-custom-payload
feature/extend-detections-with-data-field-to-support-custom-payload
2024-01-02 18:04:39 +01:00
SkalskiP e3d92a01c4 ready for colab tests 2024-01-02 17:58:08 +01:00
SkalskiP 0f6396669b initial Detections.__setitem__ implementation + Detections.__getitem__ changes 2024-01-02 17:37:26 +01:00
SkalskiP 8e40fa8664 Merge remote-tracking branch 'origin/feature/extend-detections-with-data-field-to-support-custom-payload' into feature/extend-detections-with-data-field-to-support-custom-payload 2024-01-02 15:58:54 +01:00
SkalskiP a10b9840af initial Detections.__iter__ implementation 2024-01-02 15:58:44 +01:00
pre-commit-ci[bot] 51694819e3 fix(pre_commit): 🎨 auto format pre-commit hooks 2024-01-02 14:05:34 +00:00
SkalskiP ced9f35b6e initial Detections.__getitem__ implementation 2024-01-02 15:05:20 +01:00
Onuralp SEZER b300c59f78 Merge pull request #704 from roboflow/dependabot/pip/pytest-7.4.4
⬆️ Bump pytest from 7.4.3 to 7.4.4
2024-01-01 08:38:15 +03:00
dependabot[bot] d3cbad4aa1 ⬆️ Bump pytest from 7.4.3 to 7.4.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.3 to 7.4.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.4.3...7.4.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 01:20:51 +00:00
Brad Dwyer 310a09859d Remove unused tracker_length 2023-12-29 11:42:25 -06:00
pre-commit-ci[bot] e75e527925 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-29 17:24:37 +00:00
SkalskiP 5984d3374c better Detections.merge validation 2023-12-29 18:24:24 +01:00
SkalskiP 099d36011d better Detections.merge docs + more Detections.merge tests 2023-12-29 16:53:41 +01:00
dependabot[bot] 50f3de3483 ⬆️ Bump mkdocs-material from 9.5.2 to 9.5.3 (#691)
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.5.2 to 9.5.3.
- [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.2...9.5.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-29 18:40:50 +03:00
pre-commit-ci[bot] ea21a75135 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-29 15:37:49 +00:00
SkalskiP 955220f25f Merge remote-tracking branch 'origin/feature/extend-detections-with-data-field-to-support-custom-payload' into feature/extend-detections-with-data-field-to-support-custom-payload
# Conflicts:
#	supervision/detection/core.py
2023-12-29 16:37:31 +01:00
SkalskiP 95e2ad6d52 refactor of core.py; moving utils to utils.py 2023-12-29 16:36:54 +01:00
pre-commit-ci[bot] db245bbc34 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-29 15:15:48 +00:00
SkalskiP 9be71da888 handle one more edge case in Detections.merge logic 2023-12-29 16:15:36 +01:00
SkalskiP c2412379c4 Merge remote-tracking branch 'origin/feature/extend-detections-with-data-field-to-support-custom-payload' into feature/extend-detections-with-data-field-to-support-custom-payload 2023-12-29 15:16:46 +01:00
pre-commit-ci[bot] 63ccc98d0b fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-29 14:15:59 +00:00
SkalskiP 14761cb20a fix test_detections_from_xml_obj 2023-12-29 15:15:57 +01:00
SkalskiP 5dfc2e61e7 Merge remote-tracking branch 'origin/feature/extend-detections-with-data-field-to-support-custom-payload' into feature/extend-detections-with-data-field-to-support-custom-payload 2023-12-29 15:15:49 +01:00
SkalskiP 701b0c0b97 fix test_detections_from_xml_obj 2023-12-29 15:15:38 +01:00
pre-commit-ci[bot] 27eb823809 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-29 14:05:21 +00:00
SkalskiP efed23f64e Detections.merge updated and tested 2023-12-29 15:05:07 +01:00
Christoforos Aristeidou 4d955c8531 Merge branch 'round-edge-annotator' into develop 2023-12-29 11:05:43 +02:00
Christoforos Aristeidou bbc9374f06 🎨 pre-commit class sort 2023-12-29 11:03:40 +02:00
Christoforos Aristeidou 921256548e 🎨 pre-commit space correction 2023-12-29 11:03:16 +02:00
Christoforos Aristeidou b68c019fe1 shorted description of annotate method to fit 88 chars 2023-12-29 10:55:37 +02:00
Christoforos Aristeidou 055d06b56f changed default value of roundness 2023-12-29 10:52:57 +02:00
Christoforos Aristeidou 5274147856 description for annotate method of RoundBoundingBoxAnnotator 2023-12-29 10:47:05 +02:00
Christoforos Aristeidou 2b8c31a481 class description correction 2023-12-29 10:41:03 +02:00
Christoforos Aristeidou 0bd9862f8a Class description for RoundBoundingBoxAnnotator 2023-12-29 10:40:14 +02:00
Christoforos Aristeidou 587ed25f49 added RoundBoundingBoxAnnotator to __init__ import 2023-12-29 10:36:24 +02:00
Christoforos Aristeidou df6b628a30 added RoundBoundingBoxAnnotator class annotator 2023-12-29 10:20:33 +02:00
Piotr Skalski 456ec9a847 Merge pull request #701 from roboflow/md5_recheck_fix
fix(md5): 🐞 hash_new param fix for downloaded content check
2023-12-29 09:19:37 +01:00
Onuralp SEZER 004bc7e0b3 Merge pull request #680 from HinePo/develop - Adding heatmap example
Adding heatmap example
2023-12-29 00:27:13 +03:00
Onuralp SEZER a2dbe9e53a docs(example): readme.md usage fixes
feat: default video set to people-walking.mp4 output to output.mp4
fix: re-create requirements.txt(fix end of line corruption)

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-29 00:24:40 +03:00
Onuralp SEZER fcd6866337 fix(md5): 🐞 hash_new param fix for downloaded content check
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-28 23:59:31 +03:00
Onuralp SEZER 7425303382 Merge pull request #692 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-12-28 23:33:50 +03:00
pre-commit-ci[bot] bf427d5061 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-28 18:21:48 +00:00
Brad Dwyer 8ab7cb659c Merge branch 'prediction-smoothing' of https://github.com/roboflow/supervision into prediction-smoothing 2023-12-28 12:21:38 -06:00
Brad Dwyer a58c8ef0fe Add set_length and use deque 2023-12-28 12:21:07 -06:00
pre-commit-ci[bot] 3e0a665ef2 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-28 18:04:43 +00:00
Brad Dwyer 3a0682db08 Remove NoneDict and add type hints 2023-12-28 12:04:33 -06:00
Brad Dwyer a36b426dff Merge branch 'develop' into prediction-smoothing 2023-12-28 11:50:15 -06:00
Brad Dwyer 3f77433f2e Merge branch 'prediction-smoothing' of https://github.com/roboflow/supervision into prediction-smoothing 2023-12-28 11:50:12 -06:00
Brad Dwyer 5d1e76fbd0 Update copy based on feedback from James & Piotr 2023-12-28 11:50:06 -06:00
pre-commit-ci[bot] 6600d7533a fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-28 17:43:55 +00:00
Brad Dwyer 1d4d7dd4ea Move into tools directory 2023-12-28 11:42:55 -06:00
pre-commit-ci[bot] b2d98fe457 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-28 16:52:43 +00:00
SkalskiP ea6439b8fd Detections.__eq__ updated and tested 2023-12-28 17:52:25 +01:00
pre-commit-ci[bot] f2031d53d6 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-28 15:03:47 +00:00
SkalskiP f3f545d893 simplifying Detections.__eq__ method 2023-12-28 15:58:51 +01:00
Piotr Skalski d0c2b145a8 Merge pull request #687 from roboflow/add-zoominfo
Add ZoomInfo integration
2023-12-28 14:33:16 +01:00
Brad Dwyer d7420c545e Move video to correct spot in the docs 2023-12-27 15:17:28 -06:00
Brad Dwyer 729eb16ea6 Merge branch 'prediction-smoothing' of https://github.com/roboflow/supervision into prediction-smoothing 2023-12-27 15:15:31 -06:00
Brad Dwyer ca6ba30375 Fix linter errors 2023-12-27 15:15:18 -06:00
pre-commit-ci[bot] 7f4b27a556 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-27 21:09:26 +00:00
Brad Dwyer ffdab06376 Update Docs 2023-12-27 15:02:02 -06:00
Brad Dwyer b912db7a06 Add Detections Smoother 2023-12-27 14:13:40 -06:00
pre-commit-ci[bot] db8bdc1965 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.8 → v0.1.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.8...v0.1.9)
2023-12-25 17:43:46 +00:00
Paul f942d89881 Added inference examples throughout the docs. 2023-12-22 11:09:39 -07:00
Onuralp SEZER 404adc30dd Merge pull request #690 from roboflow/dependabot/pip/mypy-1.8.0
⬆️ Bump mypy from 1.7.1 to 1.8.0
2023-12-22 12:16:49 +03:00
dependabot[bot] 9ba46fd067 ⬆️ Bump mypy from 1.7.1 to 1.8.0
Bumps [mypy](https://github.com/python/mypy) from 1.7.1 to 1.8.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.7.1...v1.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-22 09:05:20 +00:00
Onuralp SEZER 054602b4dc Merge pull request #689 from roboflow/dependabot/pip/ruff-0.1.9
⬆️ Bump ruff from 0.1.8 to 0.1.9
2023-12-22 12:03:18 +03:00
dependabot[bot] 354895585e ⬆️ Bump ruff from 0.1.8 to 0.1.9
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.8 to 0.1.9.
- [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.1.8...v0.1.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-22 00:44:40 +00:00
pre-commit-ci[bot] 587a69f00e fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-21 15:03:16 +00:00
James Gallagher 1981de1c80 use new organization 2023-12-21 15:03:04 +00:00
James 0faf14229c Update mkdocs.yml 2023-12-21 14:55:06 +00:00
Onuralp SEZER f0e7c0c847 ci: 👷 close dependabot warning and PR requests for min version(py38)
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-19 16:53:59 +03:00
Onuralp SEZER 8bcfefb672 Merge pull request #681 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-12-18 20:57:59 +03:00
pre-commit-ci[bot] d32b490afe chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/pycqa/isort: 5.13.0 → 5.13.2](https://github.com/pycqa/isort/compare/5.13.0...5.13.2)
- [github.com/astral-sh/ruff-pre-commit: v0.1.7 → v0.1.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.7...v0.1.8)
2023-12-18 17:46:43 +00:00
Onuralp SEZER 263d88bf77 docs: 📝 typos fixed in example documentation and new person added into example list
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-18 20:06:34 +03:00
Onuralp SEZER c18f9bf625 chore(formatter): 🧹 files formatting fixed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-18 20:01:04 +03:00
pre-commit-ci[bot] 670e9c5afc fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-18 15:18:55 +00:00
Rafael Levy e320db492c adding heatmap example
I haven't figured out how to add the video output file, but I can link the file below:

https://www.kaggle.com/code/hinepo/yolov8-supervision-heatmap-track-count/output?select=heatmap_and_track.mp4
2023-12-18 12:13:15 -03:00
Paul 2c833108cc Merge branch 'feature/from-roboflow-base-model' of https://github.com/roboflow/supervision into feature/from-roboflow-base-model 2023-12-18 07:07:13 -07:00
Paul 678156c1f1 Missed a couple README updates with last commit 2023-12-18 07:06:45 -07:00
pre-commit-ci[bot] e2bb2be9b2 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-18 14:03:00 +00:00
Paul 362e9f7b43 Address some review feedback:
- separated args list in examples between inference and ultralytics
- added depricated decorator to from_roboflow
- use `with supress(...)` for parsing inference response models instead of checking instance type (no more pydantic dep)
- a few other README changes
2023-12-18 06:59:59 -07:00
Onuralp SEZER 62066c92a8 Merge pull request #669 from roboflow/dependabot/pip/mkdocs-material-9.5.2
⬆️ Bump mkdocs-material from 9.5.0 to 9.5.2
2023-12-17 12:39:38 +03:00
Onuralp SEZER c64bc1cfa0 Merge pull request #674 from roboflow/dependabot/pip/ruff-0.1.8
⬆️ Bump ruff from 0.1.7 to 0.1.8
2023-12-17 12:39:20 +03:00
Onuralp SEZER 4b728334e7 Merge pull request #675 from roboflow/dependabot/pip/isort-5.13.2
⬆️ Bump isort from 5.12.0 to 5.13.2
2023-12-17 12:38:33 +03:00
Paul 973d26c180 Merge branch 'feature/from-roboflow-base-model' of https://github.com/roboflow/supervision into feature/from-roboflow-base-model 2023-12-15 09:51:11 -07:00
Paul 38cb7d7249 Add pydantic dependancy 2023-12-15 09:50:26 -07:00
pre-commit-ci[bot] 109ff2db6c fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-15 16:42:53 +00:00
Paul af5861557b Added examples using inference to each example directory and updated requirements and READMEs accordingly. 2023-12-15 09:38:05 -07:00
Paul Guerrie 2f0b10a36d WIP: Small update to accept BaseModel type for from_roboflow method.
Also adding Inference examples.
2023-12-14 22:24:09 +00:00
dependabot[bot] 5a28378d3c ⬆️ Bump isort from 5.12.0 to 5.13.2
Bumps [isort](https://github.com/pycqa/isort) from 5.12.0 to 5.13.2.
- [Release notes](https://github.com/pycqa/isort/releases)
- [Changelog](https://github.com/PyCQA/isort/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pycqa/isort/compare/5.12.0...5.13.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 00:21:00 +00:00
dependabot[bot] c210362389 ⬆️ Bump ruff from 0.1.7 to 0.1.8
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.7 to 0.1.8.
- [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.1.7...v0.1.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 00:17:42 +00:00
Piotr Skalski 5b7e0bac5a Add count_people_in_zone example to README.md 2023-12-13 15:56:37 +01:00
Piotr Skalski 2180719183 Merge pull request #673 from roboflow/example/count_people_in_zone
example/count_people_in_zone
2023-12-13 15:55:11 +01:00
pre-commit-ci[bot] d71cb82a87 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-13 14:46:54 +00:00
SkalskiP 770d7893c6 Final README.md updates 2023-12-13 15:45:14 +01:00
Piotr Skalski 6ec5c24d7e Update README.md with example results 2023-12-13 15:34:47 +01:00
pre-commit-ci[bot] e8df6e6795 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-13 14:01:56 +00:00
SkalskiP a967d78021 Merge remote-tracking branch 'origin/example/count_people_in_zone' into example/count_people_in_zone 2023-12-13 14:59:31 +01:00
SkalskiP b678d44182 Changing annotation style from BoxCornerAnnotator to BoundingBoxAnnotator. 2023-12-13 14:58:43 +01:00
pre-commit-ci[bot] 697704354a fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-13 13:46:32 +00:00
SkalskiP 5f7ad5f4d3 Update README.md in example projects. 2023-12-13 14:45:17 +01:00
pre-commit-ci[bot] f7a3a408fa fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-13 13:29:42 +00:00
SkalskiP 852eec4c6a Initial commit 🎉 2023-12-13 14:28:16 +01:00
dependabot[bot] 0b7a376ace ⬆️ Bump mkdocs-material from 9.5.0 to 9.5.2
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.5.0 to 9.5.2.
- [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.0...9.5.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-13 10:15:33 +00:00
Piotr Skalski 78a63501bf Merge pull request #672 from roboflow/doc-formatter-config
fix(black):  🔥 retire black formatter in favor of ruff and exclude doc-string long line formatter
2023-12-13 11:13:16 +01:00
Piotr Skalski 0d424a1e0b Merge pull request #671 from roboflow/md5-sec
fix(sec-md5): 🐞 md5 security warning fix
2023-12-13 11:03:30 +01:00
Onuralp SEZER 72f2c986de style(flake): 🔥 flake8 removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-13 13:01:29 +03:00
Onuralp SEZER 5f11ef4df6 fix(flake):  🧹 flake8 ignores removed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-13 12:47:15 +03:00
Onuralp SEZER 64b395ea60 fix(black):  🔥 black removed from poetry and lock file
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-13 12:38:02 +03:00
Onuralp SEZER bf338eea4a feat(ruff-format):  ✨ ruff-format added and jupyter notebook formatted
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-13 12:36:31 +03:00
Onuralp SEZER 87985b2fe2 fix(black):  🔥 retire black formatter in favor of ruff
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-13 12:28:51 +03:00
Onuralp SEZER f50976992c fix(sec-md5): 🐞 md5 security warning fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-13 12:21:14 +03:00
Piotr Skalski d68cd95d43 Merge pull request #666 from roboflow/add-tox
feat(tox): ✨ initial tox.ini for testing multiple python versions locally for supervision
2023-12-12 13:56:56 +01:00
Piotr Skalski bcf7e7b1f7 Merge pull request #573 from roboflow/add-tf-data-loader
Add `sv.Detections.from_tensorflow_hub` data loader.
2023-12-12 13:50:01 +01:00
Onuralp SEZER 16c382e0cc Merge branch 'develop' into add-tox 2023-12-12 15:49:31 +03:00
Onuralp SEZER 63616b95f7 fix(format): 🐞 supervision/detection/core.py excluded from black and flake check
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-12 15:45:03 +03:00
Piotr Skalski 634ab4ff0b Merge pull request #665 from roboflow/defusedxml-hash-security
feat(xml-parsing): 🔐 enhance security with defusedxml and bandit rules
2023-12-12 13:26:54 +01:00
James Gallagher c43b699113 update docstring example 2023-12-12 11:42:35 +00:00
Onuralp SEZER dbf5b67657 Merge pull request #667 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-12-12 00:35:02 +03:00
pre-commit-ci[bot] ed54a57575 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/PyCQA/bandit: 1.7.5 → 1.7.6](https://github.com/PyCQA/bandit/compare/1.7.5...1.7.6)
- [github.com/pycqa/isort: 5.12.0 → 5.13.0](https://github.com/pycqa/isort/compare/5.12.0...5.13.0)
- [github.com/astral-sh/ruff-pre-commit: v0.1.6 → v0.1.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.6...v0.1.7)
2023-12-11 17:44:55 +00:00
Onuralp SEZER 769c97fa49 feat(tox): ✨ initial tox.ini for multiple python version and pytest added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-10 14:42:45 +03:00
Onuralp SEZER daf4046fd2 feat(xml-parsing): 🔐 enhance security with defusedxml and bandit rules
fix bandit rule B318: (xml-attribute-parsing) defusedxml package should be used to parse untrusted XML data
fix bandit rule B314: (xml-entity-expansion) XML entity expansion should be disabled
fix bandit rule B413: (xml-etree-parse) XML parsing library should be secure
fix bandit rule B412: (xml-lib-exploits) XML libraries should be vetted for defusedxml or lxml.vulns
fix bandit rule B410: (xml-minidom-xxe) XML minidom can be vulnerable to XML eXternal Entity attacks

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-10 13:57:51 +03:00
SkalskiP 18fa772dbb Correct example usage of get_video_frames_generator in video.py. 2023-12-08 17:02:52 +01:00
Piotr Skalski 41711fe076 Merge pull request #664 from roboflow/main
Merge pull request #663 from roboflow/develop
2023-12-08 17:00:22 +01:00
SkalskiP e0c7c1fbf0 Replace misspelled function name in detection.core.py
Changed the function name from 'from_mmdet' to 'from_mmdetection'. This was done to correct a misspelling which might otherwise lead to confusion and potential errors when calling the function.
2023-12-08 16:57:41 +01:00
Piotr Skalski bcb26f9edd Merge pull request #663 from roboflow/develop
`supervision-0.17.1` release
2023-12-08 15:09:58 +01:00
SkalskiP ee697cad3e Update version number to 0.17.1 in pyproject.toml
The version number in `pyproject.toml` has been updated from 0.17.1rc2 to 0.17.1, reflecting the latest stable release of the Supervision package.
2023-12-08 15:05:49 +01:00
Piotr Skalski a53e39d097 Merge pull request #660 from roboflow/example-fixes
fix(examples): 🐞 tracking LabelAnnotator and traffic_analysis deps fixed
2023-12-08 15:03:07 +01:00
SkalskiP 08f7838f1f Changed the version number in the pyproject.toml from 0.17.1rc1 to 0.17.1rc2 for the Supervision package. 2023-12-08 14:53:49 +01:00
SkalskiP 4388f03a51 The version of the Supervision package has been updated from "0.17.0" to "0.17.1rc1". 2023-12-08 09:39:26 +01:00
Piotr Skalski f2334936e6 Merge pull request #659 from roboflow/py12-upgrade
feat: ✨ Python 3.12 support added
2023-12-08 09:37:30 +01:00
Onuralp SEZER 6d3c7f7e1d feat(notebook): ✨ using supervision[assets] instead of wget download in demo notebook
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-08 05:34:13 +03:00
Onuralp SEZER 180fdf2168 fix(examples): 🐞 tracking LabelAnnotator and traffic_analysis deps fixed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-08 02:56:23 +03:00
Onuralp SEZER 4079188368 Merge branch 'develop' into py12-upgrade
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-08 00:09:48 +03:00
Onuralp SEZER e42770eedb feat(py-version): ✨ Python 3.12 support added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-07 19:54:52 +03:00
Onuralp SEZER 2f6195ad5d Merge pull request #657 from roboflow/dependabot/github_actions/actions/setup-python-5
⬆️ Bump actions/setup-python from 4 to 5
2023-12-07 19:13:36 +03:00
SkalskiP 29a2bb726b Refactor detection conversion method in Supervision
Modified the method of converting TensorFlow detection results to match the Detections class within the Supervision package.
2023-12-07 12:16:53 +01:00
Piotr Skalski cec537cb89 Merge pull request #655 from roboflow/main
Merge pull request #627 from roboflow/develop
2023-12-07 11:07:15 +01:00
pre-commit-ci[bot] 0ab35b1d88 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-07 09:28:04 +00:00
James Gallagher 32bf235b39 add type hints, remove comment 2023-12-07 09:26:40 +00:00
dependabot[bot] ef292fe2a8 ⬆️ Bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-07 00:47:37 +00:00
Piotr Skalski 36ab9dcb8e Merge pull request #627 from roboflow/develop
`supervision-0.17.0` release
2023-12-06 15:50:31 +01:00
SkalskiP 01d6c5386a Update Supervision package to version 0.17.0
The package version has been updated from 0.17.0rc8 to 0.17.0. Alongside the version, the changelog has also been updated to reflect the newly introduced or modified features, improvements in existing features, and bug fixes.
2023-12-06 15:48:03 +01:00
SkalskiP 7a1863835b Refactor Detections function's docstrings in core.py 2023-12-06 15:26:04 +01:00
Piotr Skalski fb66e57103 Update README.md 2023-12-06 14:37:45 +01:00
SkalskiP b87e07a06b Bump version to 0.17.0rc8
The version of the supervision package in pyproject.toml has been updated from `0.17.0rc7` to `0.17.0rc8`.
2023-12-06 14:03:34 +01:00
Piotr Skalski ba79dba26e Merge pull request #652 from roboflow/feature/add_triangle_annotator
Add `TriangleAnnotator` to annotators
2023-12-06 14:01:42 +01:00
SkalskiP 721935144b Merge remote-tracking branch 'origin/feature/add_triangle_annotator' into feature/add_triangle_annotator 2023-12-06 13:59:14 +01:00
SkalskiP 26ad007b7c Add TriangleAnnotator example to documentation 2023-12-06 13:59:05 +01:00
pre-commit-ci[bot] c46ff15143 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 12:52:06 +00:00
SkalskiP f73829e941 The function was initially determining the center point of the triangle, which did not align with the desired annotation style. The changes now ensure that 'xy' refers to the coordinate of the triangle's tip instead of its center. 2023-12-06 13:51:01 +01:00
pre-commit-ci[bot] bf5d8ac29c fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 12:46:12 +00:00
SkalskiP 84713239ee Adjusted the default position value in the TriangleAnnotator class. 2023-12-06 13:45:56 +01:00
pre-commit-ci[bot] 8d9228f7fd fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 12:43:56 +00:00
SkalskiP 4400ae05eb Merge remote-tracking branch 'origin/feature/add_triangle_annotator' into feature/add_triangle_annotator
# Conflicts:
#	supervision/annotators/core.py
2023-12-06 13:43:37 +01:00
SkalskiP 366d39db48 Refactor vertices calculation in TriangleAnnotator 2023-12-06 13:42:52 +01:00
pre-commit-ci[bot] a618b7c369 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 12:34:55 +00:00
SkalskiP f94a8cb9a1 Add TriangleAnnotator to annotators
Added the ability to draw triangle markers on an image based on the provided detections with the TriangleAnnotator class. This is useful when needing to specifically mark or highlight certain areas of an image. The user can now specify both the color of the annotation and the metrics of the triangle such as base and height, as well as its position.
2023-12-06 13:32:48 +01:00
Piotr Skalski 186727243f Merge pull request #511 from abhishek7kalra/traceannotator
Fixed TraceAnnotator to respect the postion argument.
2023-12-06 13:16:50 +01:00
pre-commit-ci[bot] 7ea8e75a78 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 11:53:45 +00:00
SkalskiP 27979cf756 Simpler fix with self.trace = Trace(max_size=trace_length, anchor=position) 2023-12-06 12:50:46 +01:00
Piotr Skalski a8c1431392 Merge pull request #651 from roboflow/feature/scale_boxes_utility
Add `scale_boxes` function to detection utils
2023-12-06 12:37:00 +01:00
SkalskiP 58c8620a6f Add examples to move_boxes and scale_boxes functions 2023-12-06 12:32:59 +01:00
pre-commit-ci[bot] 9468f00997 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 11:23:31 +00:00
SkalskiP 55f5f6a97a The update introduces two new functions, move_boxes and scale_boxes, to the detection utilities in the supervision package. 2023-12-06 12:23:15 +01:00
pre-commit-ci[bot] a530b2ba5e fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-06 11:20:43 +00:00
SkalskiP 7cbf16be8a Add scale_boxes function to detection utils
Added a new function scale_boxes to the detection utilities in order to scale the dimensions of bounding boxes. This function accepts bounding boxes and a scaling factor as input and returns the scaled bounding boxes. It can enlarge or shrink the input bounding boxes based on the value of the passed factor. The function was also documented in the utils.md file and necessary tests were added to assure its correctness.
2023-12-06 12:16:22 +01:00
Piotr Skalski a112292ed0 Merge pull request #648 from roboflow/collab-fix-v2
fix(versions): 🐞 min numpy version changed to 1.21.2
2023-12-05 14:30:55 +01:00
Onuralp SEZER a64f3ff178 Merge pull request #624 from roboflow/dependabot/pip/wheel-0.42.0
⬆️ Bump wheel from 0.41.3 to 0.42.0
2023-12-05 16:28:46 +03:00
Piotr Skalski 07fc5609da Merge pull request #571 from roboflow/add-azure-analyze-image
Add `from_azure_analyze_image` data loader
2023-12-05 14:00:53 +01:00
SkalskiP 39117f19c4 Merge remote-tracking branch 'origin/add-azure-analyze-image' into add-azure-analyze-image 2023-12-05 13:57:44 +01:00
SkalskiP cb5e9c0df0 Added error handling in Detections.from_azure_analyze_image method 2023-12-05 13:57:27 +01:00
pre-commit-ci[bot] 38b87d6098 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-05 12:46:33 +00:00
SkalskiP a31f964947 Revise Detections.from_azure_analyze_image method for class mapping flexibility 2023-12-05 13:46:15 +01:00
dependabot[bot] 38297f85a5 ⬆️ Bump wheel from 0.41.3 to 0.42.0
Bumps [wheel](https://github.com/pypa/wheel) from 0.41.3 to 0.42.0.
- [Release notes](https://github.com/pypa/wheel/releases)
- [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst)
- [Commits](https://github.com/pypa/wheel/compare/0.41.3...0.42.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-05 12:44:47 +00:00
Onuralp SEZER 5cf91676f6 Merge pull request #644 from roboflow/dependabot/pip/ruff-0.1.7
⬆️ Bump ruff from 0.1.6 to 0.1.7
2023-12-05 15:32:23 +03:00
Onuralp SEZER c3c934f8c1 fix(versions): 🐞 min numpy version changed to 1.21.2
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-05 15:03:16 +03:00
SkalskiP f46326b7e4 Merge branch 'develop' into add-azure-analyze-image 2023-12-05 13:02:10 +01:00
Piotr Skalski 679fee9f16 Merge pull request #646 from roboflow/rename-boxmask-annotator
Rename `BoxMaskAnnotator` to `ColorAnnotator`
2023-12-05 12:54:49 +01:00
SkalskiP 4774ace3c2 Merge branch 'develop' into rename-boxmask-annotator 2023-12-05 12:47:48 +01:00
Piotr Skalski 2e7ecdd418 Merge pull request #647 from roboflow/collab-min-max-version-fix
fix(format): 🐞 removal of numpy,matplotlib,pillow max versions for flexible to collab updates
2023-12-05 12:46:18 +01:00
Onuralp SEZER 918970e7d6 fix(format): 🐞 removal of numpy,matplotlib,pillow max versions for flexible to collab updates
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-12-05 14:41:47 +03:00
SkalskiP 87979384ed Update project version in pyproject.toml file
The project version in the pyproject.toml file has been updated from 0.17.0rc6 to 0.17.0rc7.
2023-12-05 12:14:28 +01:00
Piotr Skalski 83603e3677 Merge pull request #633 from roboflow/add-piexlate-annotator
Add `PixelateAnnotator`
2023-12-05 12:05:39 +01:00
pre-commit-ci[bot] 566a9296d0 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-05 11:04:16 +00:00
SkalskiP 9612fe7849 Refactor PixelateAnnotator and update docs 2023-12-05 12:03:59 +01:00
James Gallagher 7f2b62a5ce show transparent image 2023-12-05 10:42:31 +00:00
James Gallagher 9c10308abc change heading 2023-12-05 10:42:05 +00:00
James Gallagher d53181bb97 rename variable 2023-12-05 10:41:20 +00:00
pre-commit-ci[bot] 9d836faa8a fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-05 10:39:27 +00:00
James Gallagher c46e0f5c97 rename BoxMaskAnnotator to ColorAnnotator 2023-12-05 10:38:32 +00:00
dependabot[bot] c322cf8001 ⬆️ Bump ruff from 0.1.6 to 0.1.7
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.6 to 0.1.7.
- [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.1.6...v0.1.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-05 00:29:12 +00:00
Piotr Skalski b69eea47a9 Update 🔥 quick start section in README.md 2023-12-04 21:37:30 +01:00
Piotr Skalski fe9b422185 Update 🔥 quick start section in README.md 2023-12-04 21:28:01 +01:00
Piotr Skalski d6fd1b0644 Merge pull request #643 from roboflow/og-images
Add open graph images to documentation.
2023-12-04 18:49:22 +01:00
James Gallagher 1ef1622126 add lenny 2023-12-04 17:03:05 +00:00
James Gallagher e45e1e277b resubmit mkdocs pr 2023-12-04 17:02:44 +00:00
Piotr Skalski b1ac5bc876 Merge pull request #566 from roboflow/min-ver-settings
build(deps): 🚀 min and max supervision package requirements are added
2023-12-04 18:02:04 +01:00
Onuralp SEZER 178d91eaa0 Merge pull request #639 from roboflow/add-open-graph-images
Add mkdocs-material[imaging] dependency
2023-12-04 19:31:26 +03:00
Onuralp SEZER 726ad1dbb1 Merge branch 'develop' into min-ver-settings 2023-12-04 19:23:20 +03:00
SkalskiP e08e4ee389 Rename calculate_dynamic_font_scale to calculate_dynamic_text_scale 2023-12-04 17:05:49 +01:00
SkalskiP 23a58ef99e Rename calculate_dynamic_font_scale to calculate_dynamic_text_scale 2023-12-04 17:04:07 +01:00
SkalskiP bd4208ce84 Update project version to 0.17.0rc5
The project version in the `pyproject.toml` file has been updated to `0.17.0rc5` from `0.17.0rc4`.
2023-12-04 16:48:04 +01:00
Piotr Skalski dd16f917d5 Merge pull request #637 from roboflow/feature/dynamic_font_scale_and_line_thicness_calculation
dynamic font scale and line thickness calculation based on image resolution
2023-12-04 16:36:48 +01:00
Piotr Skalski 31d60734bf Merge pull request #638 from roboflow/revert-636-add-open-graph-images
Revert "Add open graph images"
2023-12-04 16:26:14 +01:00
Piotr Skalski 4483970638 Revert "Add open graph images" 2023-12-04 16:22:38 +01:00
James Gallagher 1710021ece add mkdocs-material[imaging] dependency 2023-12-04 15:22:23 +00:00
Piotr Skalski 144df44ccc Merge pull request #636 from roboflow/add-open-graph-images
Add open graph images
2023-12-04 16:16:37 +01:00
James Gallagher 92761752a0 respond to feedback 2023-12-04 15:09:23 +00:00
James Gallagher b047e061e7 respond to feedback 2023-12-04 15:08:51 +00:00
pre-commit-ci[bot] 72497f3f85 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-04 14:57:58 +00:00
SkalskiP 478c3adfe2 Merge remote-tracking branch 'origin/feature/dynamic_font_scale_and_line_thicness_calculation' into feature/dynamic_font_scale_and_line_thicness_calculation 2023-12-04 15:57:43 +01:00
SkalskiP 81d0876838 Added two new utility functions in the supervision module for dynamic font-size scaling and line thickness calculations. 2023-12-04 15:57:27 +01:00
Piotr Skalski 66720c58fd Merge pull request #635 from roboflow/add-code-snippet-copy
Add code snippet copy feature to docs
2023-12-04 15:30:26 +01:00
pre-commit-ci[bot] b16e479a14 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-04 14:29:14 +00:00
SkalskiP 9f5773aa70 This commit adds descriptions for two new utility functions: calculate_dynamic_font_scale and calculate_dynamic_line_thickness. 2023-12-04 15:27:01 +01:00
SkalskiP d2d590834e Added dynamic font scale and line thickness calculations in utils.py. 2023-12-04 15:18:55 +01:00
pre-commit-ci[bot] f046940bb5 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-04 14:08:00 +00:00
James Gallagher e7e542d160 add required import 2023-12-04 14:07:25 +00:00
James Gallagher dd19c4e185 work on annotator 2023-12-04 14:05:49 +00:00
James Gallagher dfb703219e work on annotator 2023-12-04 14:04:59 +00:00
James Gallagher ec8f10d6a8 add open graph images 2023-12-04 13:35:27 +00:00
capjamesg 242ac0cd06 add code snippet copy feature to docs 2023-12-04 13:20:13 +00:00
pre-commit-ci[bot] 8946d44dcb fix(pre_commit): 🎨 auto format pre-commit hooks 2023-12-04 13:16:58 +00:00
capjamesg 718f1b077d add pixelate annotator 2023-12-04 13:15:45 +00:00
Onuralp SEZER 93eb48c2a0 Merge pull request #629 from roboflow/dependabot/pip/cryptography-41.0.6
⬆️ Bump cryptography from 41.0.4 to 41.0.6
2023-12-01 23:33:09 +03:00
dependabot[bot] f6265ebbda ⬆️ Bump cryptography from 41.0.4 to 41.0.6
Bumps [cryptography](https://github.com/pyca/cryptography) from 41.0.4 to 41.0.6.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/41.0.4...41.0.6)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 20:25:38 +00:00
Piotr Skalski b94e2796bd Merge pull request #631 from roboflow/dependabot/github_actions/actions/first-interaction-1.3.0 2023-11-30 11:44:28 +01:00
dependabot[bot] e77d06d817 ⬆️ Bump actions/first-interaction from 1.2.0 to 1.3.0
Bumps [actions/first-interaction](https://github.com/actions/first-interaction) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/actions/first-interaction/releases)
- [Commits](https://github.com/actions/first-interaction/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: actions/first-interaction
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-30 00:38:11 +00:00
Piotr Skalski b63457e5fa Merge pull request #478 from roboflow/add-classification-annotator
Add `sv.Classifications.from_clip` data loader
2023-11-27 15:33:29 +01:00
SkalskiP 575a7a301d Refactored the code in core.py to optimize softmax calculation and improve the related docstrings. 2023-11-27 15:27:39 +01:00
James Gallagher fa8f31931c fix dict data type 2023-11-27 14:16:52 +00:00
James Gallagher b4b332a0e2 fix dict data type 2023-11-27 14:14:56 +00:00
SkalskiP 02502baab3 Update docstrings and softmax calculation in core.py 2023-11-27 15:04:06 +01:00
SkalskiP 2aebe13583 Merge branch 'develop' into add-classification-annotator 2023-11-27 14:50:15 +01:00
James Gallagher 6ed04252d6 fix merge conflict 2023-11-27 13:45:16 +00:00
pre-commit-ci[bot] 491209d7bd fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-27 13:45:06 +00:00
James Gallagher 444f8d01c1 remove classification annotator 2023-11-27 13:44:52 +00:00
James Gallagher f91fad5600 fix merge conflict 2023-11-27 13:42:31 +00:00
Piotr Skalski 1589d8fd43 Merge pull request #572 from roboflow/add-timm-classification-loader
Add timm data loader for `sv.Classifications`
2023-11-27 13:05:58 +01:00
SkalskiP 1d66840cad Optimize imports in core.py
Adjustments have been made to the import statements in the 'core.py' file of the 'classification' module.
2023-11-27 12:58:34 +01:00
SkalskiP 05602cd2a0 Refactor code for clarity and better variable use
The variable names and usage within the 'ultralytics' and 'timm' functions were updated for improved code readability. The docstrings were also refined to better explain the function parameters. Instances where YOLO was redundantly called were also eliminated.
2023-11-27 12:51:05 +01:00
James fc9acc456b Merge branch 'develop' into add-classification-annotator 2023-11-27 11:18:40 +00:00
James Gallagher b6c85a3f4b fix precommit issue 2023-11-27 11:15:55 +00:00
James Gallagher ce92069ba6 fix precommit 2023-11-27 10:57:00 +00:00
Piotr Skalski 2dcf2cc2ae Merge pull request #621 from kim-jeonghyun/fix_typo_from_mmdetection
fix: 📝 typo in from_mmdetection docstring
2023-11-26 20:41:44 +01:00
kim-jeonghyun 619ec018bc fix: 📝 typo in from_mmdetection docstring 2023-11-26 20:33:37 +09:00
SkalskiP 5333eb2684 Update project version in pyproject.toml
The version of the project has been updated from "0.17.0rc3" to "0.17.0rc4".
2023-11-26 11:33:56 +01:00
Piotr Skalski d5d70052bb Merge pull request #620 from roboflow/feature/add_color_as_hex
Add 'as_hex' method and corresponding test to `Color` class.
2023-11-26 11:29:25 +01:00
pre-commit-ci[bot] 242ac5f7db fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-26 10:27:43 +00:00
SkalskiP e6f0ae8514 Add 'as_hex' method and corresponding test to Color class. 2023-11-26 11:25:59 +01:00
Onuralp SEZER 10c44b0143 Merge pull request #613 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-11-21 18:06:51 +03:00
Onuralp SEZER 2a3f592090 Merge pull request #608 from roboflow/dependabot/pip/ruff-0.1.6
⬆️ Bump ruff from 0.1.5 to 0.1.6
2023-11-21 15:18:54 +03:00
pre-commit-ci[bot] 7941527a75 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.5 → v0.1.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.5...v0.1.6)
2023-11-20 17:36:14 +00:00
Piotr Skalski 42661a0563 Merge pull request #612 from karanjakhar/fixing-typos
fixing typo TRACE -> TRACK
2023-11-20 12:25:51 +01:00
SkalskiP 32077eb11d Bump version in pyproject.toml
The version in the pyproject.toml file has been updated from 0.17.0rc2 to 0.17.0rc3.
2023-11-20 12:21:37 +01:00
karanjakhar d20083de85 fixing typo TRACE -> TRACK 2023-11-20 15:32:18 +05:30
dependabot[bot] 564f1b1026 ⬆️ Bump ruff from 0.1.5 to 0.1.6
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.5 to 0.1.6.
- [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.1.5...v0.1.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-20 01:09:24 +00:00
Piotr Skalski 145313ab8f Merge pull request #606 from xenteros/feature/Make_sv.MaskAnnotator_as_fast_as_annotators_in_popular_detection_frameworks_#472
Feature/make sv.mask annotator as fast as annotators in popular detection frameworks #472
2023-11-17 17:20:22 +01:00
xenteros 1267cf7fb0 Reformatted Code with pre-commit 2023-11-16 22:34:52 +01:00
xenteros c2101db5d2 Optimize sv.MaskAnnotator by reducing number of calls to cv2.addWeighted
* Combined all colored masks before applying them to the scene
* Made sure that returned ndarray is np.uint8 for video writer simplicity
2023-11-16 22:27:32 +01:00
Piotr Skalski fe4657f0d0 Merge pull request #605 from roboflow/feature/add_center_of_mass_text_positioning
Add centroid calculation for binary masks
2023-11-16 16:26:57 +01:00
SkalskiP 6c756c411b Add calculate_masks_centroids function import in __init__.py 2023-11-16 16:25:48 +01:00
SkalskiP 0725d5a1a9 Cast get_anchors_coordinates return to integer. 2023-11-16 15:50:37 +01:00
SkalskiP fa3b43f20a Merge remote-tracking branch 'origin/feature/add_center_of_mass_text_positioning' into feature/add_center_of_mass_text_positioning 2023-11-16 15:37:17 +01:00
SkalskiP 5e091396f2 Refactor center_coordinates conversion to tuple 2023-11-16 15:36:36 +01:00
pre-commit-ci[bot] 66448ea862 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-16 14:33:57 +00:00
SkalskiP b33d68da00 Merge remote-tracking branch 'origin/feature/add_center_of_mass_text_positioning' into feature/add_center_of_mass_text_positioning
# Conflicts:
#	supervision/annotators/core.py
2023-11-16 15:31:56 +01:00
SkalskiP 6956dad17d Swap enumeration arguments in loop 2023-11-16 15:30:03 +01:00
pre-commit-ci[bot] b92ffeff82 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-16 14:24:19 +00:00
SkalskiP 7750856c18 Fix method names and improve code formatting
Renamed methods to improve clarity. `get_anchor_coordinates` changed to `get_anchors_coordinates` and `calculate_centroids` changed to `calculate_masks_centroids`. Indentation for method arguments was adjusted in `core.py` and other files for better readability. Functionality remains the same, these changes are meant to improve code maintainability and readability.
2023-11-16 15:23:55 +01:00
pre-commit-ci[bot] 72ab46687f fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-16 12:59:16 +00:00
SkalskiP 50e561a4fb Add centroid calculation for binary masks
Added `calculate_centroids` function to compute center of mass for binary mask representations. Method added to `utils.py` and method import added to `core.py`. `Position` enumeration updated with `CENTER_OF_MASS` constant. Test function is added with test cases covering different mask scenarios. Update allows for masks to carry center of mass information too, useful in object detection.
2023-11-16 13:52:32 +01:00
Piotr Skalski bb7695a774 Merge pull request #603 from roboflow/gh-pages-permission-fix
fix: 🐞 gh-pages permission fix for deployment
2023-11-15 20:50:58 +01:00
Onuralp SEZER 95006dca14 fix: 🐞 gh-pages permission fix for deployment 2023-11-15 22:11:32 +03:00
Onuralp SEZER b3dec1a734 Merge branch 'develop' into min-ver-settings 2023-11-15 21:39:37 +03:00
Piotr Skalski 5456c666c7 Merge pull request #602 from roboflow/feature/adding-polygon-annotator
Add PolygonAnnotator and update documentation
2023-11-15 17:54:11 +01:00
SkalskiP 2ed4e16ab5 Added a visual and code example for PolygonAnnotator in supervision/annotators/core.py and docs/annotators.md. 2023-11-15 17:49:17 +01:00
SkalskiP c1beb0f5fd Add PolygonAnnotator to supervision annotators 2023-11-15 17:30:06 +01:00
pre-commit-ci[bot] 777e8d3e5b fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-15 16:11:11 +00:00
SkalskiP e40532cf3e Add PolygonAnnotator and update documentation
Implemented the PolygonAnnotator class in the core.py file under the supervision/annotators directory to support drawing polygons over detected objects. This was done by dividing the masks into multiple polygons and drawing them on the image.
2023-11-15 17:09:27 +01:00
Onuralp SEZER 550e86bc6d Merge pull request #598 from roboflow/dependabot/pip/mkdocstrings-0.24.0
⬆️ Bump mkdocstrings from 0.23.0 to 0.24.0
2023-11-15 17:07:13 +03:00
Onuralp SEZER 6af17b235f Merge pull request #589 from roboflow/dependabot/pip/mypy-1.7.0
⬆️ Bump mypy from 1.6.1 to 1.7.0
2023-11-15 17:06:48 +03:00
Onuralp SEZER de867bb166 Merge pull request #593 from roboflow/dependabot/github_actions/actions/github-script-7
⬆️ Bump actions/github-script from 6 to 7
2023-11-15 17:06:25 +03:00
Onuralp SEZER ca84d3129c Merge pull request #592 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-11-15 17:06:03 +03:00
Onuralp SEZER 9c9bc77e12 Merge pull request #600 from roboflow/fix/incorrectly-autoformatted-case-test
Updated tests to reflect changes in file content handling
2023-11-15 17:05:11 +03:00
Onuralp SEZER b9573605c7 fix(test): 🧪 pre-commit's whitespace exclude and test case fix for whiespace
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-11-15 17:01:57 +03:00
pre-commit-ci[bot] 8025b468a2 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-15 13:42:25 +00:00
SkalskiP d3fb4ad932 Ignoring W291 for test_file.py 2023-11-15 14:41:38 +01:00
pre-commit-ci[bot] fcfb57612f fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-15 13:37:51 +00:00
SkalskiP c28aa5aebd Updated tests to reflect changes in file content handling 2023-11-15 14:37:02 +01:00
Piotr Skalski 109d048a38 Merge pull request #584 from SummitStudiosDev/develop
Ignore Empty Newlines in Yolo Label File
2023-11-15 14:32:34 +01:00
dependabot[bot] 6ad1f701dd ⬆️ Bump mkdocstrings from 0.23.0 to 0.24.0
Bumps [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) from 0.23.0 to 0.24.0.
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.23.0...0.24.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-15 00:32:33 +00:00
dependabot[bot] 7f081f4314 ⬆️ Bump actions/github-script from 6 to 7
Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-14 00:36:36 +00:00
pre-commit-ci[bot] dd39360221 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/psf/black: 23.10.1 → 23.11.0](https://github.com/psf/black/compare/23.10.1...23.11.0)
- [github.com/astral-sh/ruff-pre-commit: v0.1.4 → v0.1.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.4...v0.1.5)
2023-11-13 17:46:54 +00:00
dependabot[bot] 7de7281e0e ⬆️ Bump mypy from 1.6.1 to 1.7.0
Bumps [mypy](https://github.com/python/mypy) from 1.6.1 to 1.7.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.6.1...v1.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-13 00:53:30 +00:00
Onuralp SEZER e8f0ceab71 fix: 🐞 test fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-11-10 22:07:47 +03:00
Onuralp SEZER 94a95110ce fix: 🐞 pre-commit fix and ignore removed (not needed)
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-11-10 21:47:40 +03:00
pre-commit-ci[bot] 08a48a4f5d fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-10 18:26:26 +00:00
SkalskiP 95f4b5c0b8 Add linting rule exceptions for test_file.py
Added linting rule exceptions for 'test/utils/test_file.py' in 'pyproject.toml'. Specifically, the 'W291' error which checks for trailing whitespace is ignored for this test file. This is necessary to test whether 'read_txt_file' function in 'test_utils.py' correctly ignores trailing whitespaces in varies test scenarios.
2023-11-10 10:25:59 -08:00
pre-commit-ci[bot] 6211139201 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-10 18:15:39 +00:00
SkalskiP e416ef4c0e Refactor import paths and improve text file reading
Refactored import paths for test utility methods across multiple test files to align with a recent package restructure. Enriched 'read_txt_file' functionality in 'file.py' allowing to optionally skip empty lines, enhancing flexibility for various use-cases. Added tests for the new 'read_txt_file' behavior in a new 'test_file.py'. Renamed 'utils.py' in test package to 'test_utils.py' for better differentiation from the util package in the source code.
2023-11-10 10:15:08 -08:00
pre-commit-ci[bot] 1dce43747f fix(pre_commit): 🎨 auto format pre-commit hooks 2023-11-10 04:41:51 +00:00
Cody Chen f9ead5543b Ignore empty newlines in yolo label file 2023-11-09 20:24:11 -08:00
Onuralp SEZER 5d19e246a4 Merge pull request #583 from roboflow/dependabot/pip/ruff-0.1.5
⬆️ Bump ruff from 0.1.4 to 0.1.5
2023-11-09 11:33:03 +03:00
Onuralp SEZER 052a9d33bb Merge pull request #582 from roboflow/dependabot/pip/black-23.11.0
⬆️ Bump black from 23.10.1 to 23.11.0
2023-11-09 11:32:45 +03:00
dependabot[bot] ed41153c19 ⬆️ Bump ruff from 0.1.4 to 0.1.5
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.4 to 0.1.5.
- [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.1.4...v0.1.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-09 00:48:59 +00:00
dependabot[bot] b89487d8e8 ⬆️ Bump black from 23.10.1 to 23.11.0
Bumps [black](https://github.com/psf/black) from 23.10.1 to 23.11.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/23.10.1...23.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-09 00:46:29 +00:00
Onuralp SEZER c8f557af0c Merge pull request #578 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-11-06 21:19:40 +03:00
pre-commit-ci[bot] 7946f54b95 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.3 → v0.1.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.3...v0.1.4)
2023-11-06 17:37:29 +00:00
Onuralp SEZER eeae6dafc0 Merge pull request #577 from roboflow/dependabot/pip/ruff-0.1.4
⬆️ Bump ruff from 0.1.3 to 0.1.4
2023-11-06 18:41:42 +03:00
Onuralp SEZER d07e6a3ed2 Merge pull request #576 from roboflow/dependabot/pip/mkdocs-material-9.4.8
⬆️ Bump mkdocs-material from 9.4.7 to 9.4.8
2023-11-06 18:41:15 +03:00
dependabot[bot] 06945856a3 ⬆️ Bump ruff from 0.1.3 to 0.1.4
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.3 to 0.1.4.
- [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.1.3...v0.1.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-06 00:57:31 +00:00
dependabot[bot] 899d88676b ⬆️ Bump mkdocs-material from 9.4.7 to 9.4.8
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.4.7 to 9.4.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.4.7...9.4.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>
2023-11-06 00:54:42 +00:00
James Gallagher 1fd248f1ff upgrade to work with tf2 2023-11-03 20:11:32 +00:00
James Gallagher 417656f176 upgrade to work with tf2 2023-11-03 20:08:28 +00:00
James Gallagher 2335b61d1e move to use detection_classes for tf2 compat 2023-11-03 19:48:42 +00:00
James Gallagher d7e8a11139 add sv.Detections.from_tensorflow_hub 2023-11-03 19:31:46 +00:00
James Gallagher 82ed322fba add timm data loader 2023-11-03 18:25:09 +00:00
James Gallagher c438b16e74 update example 2023-11-03 16:11:16 +00:00
James Gallagher 3490c3e670 add azure data loader 2023-11-03 15:59:53 +00:00
Onuralp SEZER 583ad5f6e2 ci: 👷 ci job are renamed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-11-03 14:11:12 +03:00
Piotr Skalski 26eac2cdc7 Merge pull request #565 from roboflow/hb-removal-readme
docs: 🚀 hacktoberfest 2023 finished.
2023-11-03 11:51:46 +01:00
Onuralp SEZER 9a0f35fcf9 ci: 👷 python3.8 and minimum version package CI added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-11-02 22:19:35 +03:00
Onuralp SEZER 7a7b50eb12 build(deps): 🚀 min and max supervision package reqs are added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-11-02 22:17:27 +03:00
Onuralp SEZER ad458cf705 docs: 🚀 hacktoberfest 2023 finished.
Thank you all who participate to hacktoberfest to make supervision awesome ! 🎉 🎉 🎉 🎉
2023-11-02 20:38:17 +03:00
Onuralp SEZER 9f3d688bab Merge pull request #560 from roboflow/dependabot/pip/mypy-1.6.1
⬆️ Bump mypy from 1.4.1 to 1.6.1
2023-11-01 18:34:00 +03:00
Onuralp SEZER 190bfbf0d0 Merge pull request #559 from roboflow/dependabot/pip/mkdocs-material-9.4.7
⬆️ Bump mkdocs-material from 9.4.6 to 9.4.7
2023-11-01 18:33:37 +03:00
dependabot[bot] f9b8709568 ⬆️ Bump mypy from 1.4.1 to 1.6.1
Bumps [mypy](https://github.com/python/mypy) from 1.4.1 to 1.6.1.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.4.1...v1.6.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 00:37:17 +00:00
dependabot[bot] 8d1e091a3b ⬆️ Bump mkdocs-material from 9.4.6 to 9.4.7
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.4.6 to 9.4.7.
- [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.4.6...9.4.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 00:35:42 +00:00
Piotr Skalski 92592c8edc Merge pull request #555 from fdloopes/540-bug-blur-annotator
fix: #540 bug blur annotator
2023-10-31 18:25:44 +01:00
pre-commit-ci[bot] e6a5c514f8 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-31 17:05:11 +00:00
SkalskiP ce7e3a1de4 Refactor clip_boxes function and enhance detections processing
Refactored the `clip_boxes` function for clarity by renaming arguments from `boxes_xyxy` and `frame_resolution_wh` to `xyxy` and `resolution_wh`, respectively. These change makes the function arguments more intuitive and improves code readability.

The processing of detections in `supervision/annotators/core.py` has been updated to include clipping of detection boxes to the image bounds before processing. This prevents errors and ensures detections beyond the image dimensions are handled correctly. Adjustments were also made in the test cases and in `polygon_zone.py` to match the updated `clip_boxes` function.
2023-10-31 18:04:13 +01:00
Piotr Skalski 4cb19e6618 Merge pull request #558 from roboflow/fix/kapa-roboflow-logo
Update init_kapa_widget.js
2023-10-31 17:32:31 +01:00
Piotr Skalski 6e039d7ebd Update init_kapa_widget.js 2023-10-31 17:30:02 +01:00
Piotr Skalski c100c8019a Merge pull request #552 from roboflow/add-docs-bot
Add Kapa documentation bot to supervision docs
2023-10-31 17:23:49 +01:00
Onuralp SEZER e3e30e305a Merge pull request #547 from roboflow/dependabot/pip/ruff-0.1.3
⬆️ Bump ruff from 0.1.2 to 0.1.3
2023-10-31 18:54:48 +03:00
dependabot[bot] 4a5d850f28 ⬆️ Bump ruff from 0.1.2 to 0.1.3
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.2 to 0.1.3.
- [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.1.2...v0.1.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-31 15:53:12 +00:00
Onuralp SEZER 092771d9a1 Merge pull request #545 from roboflow/dependabot/pip/flake8-6.1.0
⬆️ Bump flake8 from 6.0.0 to 6.1.0
2023-10-31 18:50:19 +03:00
Onuralp SEZER 321dc054df Merge pull request #546 from roboflow/dependabot/pip/notebook-7.0.6
⬆️ Bump notebook from 6.5.4 to 7.0.6
2023-10-31 18:49:30 +03:00
dependabot[bot] ec9aae686b ⬆️ Bump notebook from 6.5.4 to 7.0.6
Bumps [notebook](https://github.com/jupyter/notebook) from 6.5.4 to 7.0.6.
- [Release notes](https://github.com/jupyter/notebook/releases)
- [Changelog](https://github.com/jupyter/notebook/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jupyter/notebook/compare/v6.5.4...@jupyter-notebook/tree@7.0.6)

---
updated-dependencies:
- dependency-name: notebook
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-31 15:48:33 +00:00
Onuralp SEZER 7c2e9842e8 Merge pull request #543 from roboflow/dependabot/pip/pillow-10.1.0
⬆️ Bump pillow from 10.0.1 to 10.1.0
2023-10-31 18:47:58 +03:00
Onuralp SEZER 4d3820ba73 Merge pull request #554 from roboflow/dependabot/pip/wheel-0.41.3
⬆️ Bump wheel from 0.40.0 to 0.41.3
2023-10-31 18:46:45 +03:00
fdloopes 8b88f1f415 Add space after comma, following pre-commit pattern 2023-10-31 11:50:37 -03:00
Onuralp SEZER 37951b3617 Merge pull request #553 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-10-31 14:06:44 +03:00
dependabot[bot] 98fa8339c8 ⬆️ Bump wheel from 0.40.0 to 0.41.3
Bumps [wheel](https://github.com/pypa/wheel) from 0.40.0 to 0.41.3.
- [Release notes](https://github.com/pypa/wheel/releases)
- [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst)
- [Commits](https://github.com/pypa/wheel/compare/0.40.0...0.41.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-31 01:05:37 +00:00
pre-commit-ci[bot] 030359cb44 chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/psf/black: 23.10.0 → 23.10.1](https://github.com/psf/black/compare/23.10.0...23.10.1)
- [github.com/astral-sh/ruff-pre-commit: v0.1.1 → v0.1.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.1...v0.1.3)
2023-10-30 17:39:35 +00:00
pre-commit-ci[bot] 9f265b4833 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-30 15:15:15 +00:00
James Gallagher c036aa9bd6 add kapa bot 2023-10-30 15:13:33 +00:00
fdloopes 7f69f6a168 Add np.maximum when retrieving detections coordinates within the BlurAnnotator.annotate() method. 2023-10-30 10:26:09 -03:00
Piotr Skalski d76dd771d7 Merge pull request #462 from Rajarshi-Misra/develop
Builds: Create "How to: track objects" docs page #442
2023-10-28 01:14:34 +02:00
pre-commit-ci[bot] 21fe102bbd fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-27 23:12:26 +00:00
SkalskiP 769f97cd7d Update object tracking documentation
Revise the contents of the 'How to Track Objects' documentation covering the use of supervision for object tracking in video analysis. The revision offers a more detailed guide, including running inference, tracking objects, annotating videos with unique tracking IDs, and annotating videos with traces. The new guide provides a structured walkthrough and tutorial on using Supervision's functionalities, aimed at helping users to annotate videos more effectively and understand the movement patterns and interactions of objects in the videos.
2023-10-28 01:12:09 +02:00
Onuralp SEZER 2de3e171f3 Merge pull request #542 from roboflow/dependabot/pip/pytest-7.4.3
⬆️ Bump pytest from 7.4.2 to 7.4.3
2023-10-26 07:20:56 +03:00
Onuralp SEZER 6a4bfcf094 Merge pull request #541 from roboflow/dependabot/pip/black-23.10.1
⬆️ Bump black from 23.7.0 to 23.10.1
2023-10-26 07:20:36 +03:00
dependabot[bot] 82e35479e7 ⬆️ Bump flake8 from 6.0.0 to 6.1.0
Bumps [flake8](https://github.com/pycqa/flake8) from 6.0.0 to 6.1.0.
- [Commits](https://github.com/pycqa/flake8/compare/6.0.0...6.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 00:26:40 +00:00
dependabot[bot] 3356defe95 ⬆️ Bump pillow from 10.0.1 to 10.1.0
Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.0.1 to 10.1.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/10.0.1...10.1.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 00:25:05 +00:00
dependabot[bot] c04129f2b8 ⬆️ Bump pytest from 7.4.2 to 7.4.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.2 to 7.4.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.4.2...7.4.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 00:24:09 +00:00
dependabot[bot] 22b4444e9e ⬆️ Bump black from 23.7.0 to 23.10.1
Bumps [black](https://github.com/psf/black) from 23.7.0 to 23.10.1.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/23.7.0...23.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 00:23:12 +00:00
Piotr Skalski 5de77cee7d Merge pull request #534 from hugoles/patch-1
Rename script.sh to setup.sh
2023-10-25 15:15:06 +02:00
Onuralp SEZER f36b39b543 Merge pull request #537 from roboflow/dependabot/pip/ruff-0.1.2
⬆️ Bump ruff from 0.1.1 to 0.1.2
2023-10-25 14:23:04 +03:00
dependabot[bot] 8e91c62103 ⬆️ Bump ruff from 0.1.1 to 0.1.2
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.1 to 0.1.2.
- [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.1.1...v0.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 11:18:29 +00:00
Onuralp SEZER ab0612917b Merge pull request #538 from roboflow/dependabot/pip/matplotlib-3.7.3
⬆️ Bump matplotlib from 3.7.2 to 3.7.3
2023-10-25 14:16:36 +03:00
Onuralp SEZER 4f31cf9f46 Merge pull request #536 from roboflow/dependabot/pip/opencv-python-headless-4.8.1.78
⬆️ Bump opencv-python-headless from 4.8.0.74 to 4.8.1.78
2023-10-25 14:15:58 +03:00
Onuralp SEZER d563d5db03 Merge pull request #535 from roboflow/dependabot/pip/mkdocstrings-0.23.0
⬆️ Bump mkdocstrings from 0.20.0 to 0.23.0
2023-10-25 14:15:08 +03:00
Onuralp SEZER f309b43c68 Merge pull request #539 from roboflow/dependabot/pip/pre-commit-3.5.0
⬆️ Bump pre-commit from 3.3.3 to 3.5.0
2023-10-25 14:14:32 +03:00
dependabot[bot] b17003855c ⬆️ Bump pre-commit from 3.3.3 to 3.5.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.3.3 to 3.5.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.3.3...v3.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 00:44:21 +00:00
dependabot[bot] 45a1905812 ⬆️ Bump matplotlib from 3.7.2 to 3.7.3
Bumps [matplotlib](https://github.com/matplotlib/matplotlib) from 3.7.2 to 3.7.3.
- [Release notes](https://github.com/matplotlib/matplotlib/releases)
- [Commits](https://github.com/matplotlib/matplotlib/compare/v3.7.2...v3.7.3)

---
updated-dependencies:
- dependency-name: matplotlib
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 00:43:41 +00:00
dependabot[bot] cbcd0be74c ⬆️ Bump opencv-python-headless from 4.8.0.74 to 4.8.1.78
Bumps [opencv-python-headless](https://github.com/opencv/opencv-python) from 4.8.0.74 to 4.8.1.78.
- [Release notes](https://github.com/opencv/opencv-python/releases)
- [Commits](https://github.com/opencv/opencv-python/commits)

---
updated-dependencies:
- dependency-name: opencv-python-headless
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 00:42:13 +00:00
dependabot[bot] bda80934cc ⬆️ Bump mkdocstrings from 0.20.0 to 0.23.0
Bumps [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) from 0.20.0 to 0.23.0.
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.20.0...0.23.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 00:41:33 +00:00
Hugo Dutra b77bab39de Rename script.sh to setup.sh
changing the file name.
2023-10-24 12:37:52 -03:00
Onuralp SEZER 599a9b8a5b Merge pull request #531 from roboflow/dependabot/pip/ruff-0.1.1
⬆️ Bump ruff from 0.0.280 to 0.1.1
2023-10-24 17:23:59 +03:00
Piotr Skalski b9dbbbc0ec Merge pull request #533 from roboflow/assets-fix
Assets fix
2023-10-24 16:16:30 +02:00
pre-commit-ci[bot] 337abe1e71 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-24 14:15:07 +00:00
SkalskiP 9ece846f8e Update project version in pyproject.toml
Increased the version of the project from "0.17.0rc1" to "0.17.0rc2" in the 'pyproject.toml' file.
2023-10-24 16:11:46 +02:00
dependabot[bot] c23d00566b ⬆️ Bump ruff from 0.0.280 to 0.1.1
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.0.280 to 0.1.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.0.280...v0.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 14:11:27 +00:00
SkalskiP 6837ef1d36 Refactor asset imports and improve documentation
Updated the import statements in the `supervision/assets/__init__.py`, `supervision/assets/downloader.py`, and `supervision/assets/list.py` files to use absolute paths for improved readability and reduced risk of import errors. Also added a usage example to the `download_assets` function to better illustrate its usage and return value.
2023-10-24 16:10:37 +02:00
Onuralp SEZER 26990513ba Merge pull request #528 from roboflow/dependabot/pip/build-1.0.3
⬆️ Bump build from 0.10.0 to 1.0.3
2023-10-24 17:09:44 +03:00
Onuralp SEZER bdf527809d Merge pull request #532 from roboflow/dependabot/pip/opencv-python-4.8.1.78
⬆️ Bump opencv-python from 4.8.0.74 to 4.8.1.78
2023-10-24 17:09:18 +03:00
dependabot[bot] 23a71e6f51 ⬆️ Bump build from 0.10.0 to 1.0.3
Bumps [build](https://github.com/pypa/build) from 0.10.0 to 1.0.3.
- [Release notes](https://github.com/pypa/build/releases)
- [Changelog](https://github.com/pypa/build/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pypa/build/compare/0.10.0...1.0.3)

---
updated-dependencies:
- dependency-name: build
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 14:02:20 +00:00
dependabot[bot] e61f1718a0 ⬆️ Bump opencv-python from 4.8.0.74 to 4.8.1.78
Bumps [opencv-python](https://github.com/opencv/opencv-python) from 4.8.0.74 to 4.8.1.78.
- [Release notes](https://github.com/opencv/opencv-python/releases)
- [Commits](https://github.com/opencv/opencv-python/commits)

---
updated-dependencies:
- dependency-name: opencv-python
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 14:00:32 +00:00
Onuralp SEZER bb79eebdae Merge pull request #530 from roboflow/dependabot/pip/mkdocs-material-9.4.6
⬆️ Bump mkdocs-material from 9.1.19 to 9.4.6
2023-10-24 17:00:17 +03:00
Onuralp SEZER cdb74c1b19 Merge pull request #529 from roboflow/dependabot/pip/pytest-7.4.2
⬆️ Bump pytest from 7.4.0 to 7.4.2
2023-10-24 16:59:15 +03:00
dependabot[bot] b1ceb1debf ⬆️ Bump mkdocs-material from 9.1.19 to 9.4.6
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.1.19 to 9.4.6.
- [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.1.19...9.4.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 13:59:09 +00:00
Onuralp SEZER 9fe343942f Merge pull request #526 from roboflow/dependabot/github_actions/actions/first-interaction-1.2.0
⬆️ Bump actions/first-interaction from 1.1.1 to 1.2.0
2023-10-24 16:58:35 +03:00
Onuralp SEZER b08d40cad4 Merge pull request #527 from roboflow/dependabot/github_actions/actions/checkout-4
⬆️ Bump actions/checkout from 3 to 4
2023-10-24 16:58:05 +03:00
dependabot[bot] 46a50e9595 ⬆️ Bump pytest from 7.4.0 to 7.4.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.0 to 7.4.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.4.0...7.4.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 13:57:57 +00:00
dependabot[bot] 7001721872 ⬆️ Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 13:56:24 +00:00
dependabot[bot] 8c2d18d752 ⬆️ Bump actions/first-interaction from 1.1.1 to 1.2.0
Bumps [actions/first-interaction](https://github.com/actions/first-interaction) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/actions/first-interaction/releases)
- [Commits](https://github.com/actions/first-interaction/compare/v1.1.1...v1.2.0)

---
updated-dependencies:
- dependency-name: actions/first-interaction
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 13:56:19 +00:00
Piotr Skalski fc8e2e2889 Merge pull request #479 from roboflow/dependabot-bot-add
ci(dependabot): 🤖 create dependabot.yml config for update github actions and python packages automatically.
2023-10-24 15:55:57 +02:00
Onuralp SEZER 14dfb32f44 Merge pull request #476 from roboflow/asset-addon
feat(assets): ✨ assets and assets downloader add-on for supervision[assets]
2023-10-24 16:53:38 +03:00
Piotr Skalski 8aee70872f Merge branch 'develop' into asset-addon 2023-10-24 15:50:56 +02:00
SkalskiP 671c8b3683 Update asset list and project version 2023-10-24 15:49:32 +02:00
SkalskiP edaef0b165 Merge remote-tracking branch 'origin/asset-addon' into asset-addon 2023-10-24 15:42:14 +02:00
SkalskiP 28fb656bca Update docstring formatting in VideoAssets enum
Updated the docstring comment's format inside the VideoAssets enum in supervision/assets/list.py. The update aligns with PEP 8 E501 error code that requires line too long (>80 characters).

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-24 16:40:26 +03:00
SkalskiP e9866c2f25 "Add instructions for assets utility installation
Expanded the documentation to include instructions on how to install and use the Supervision assets utility. Instructions include steps for performing the installation using pip, allowing users to easily download video files for their demos.
2023-10-24 15:40:19 +02:00
SkalskiP e59d1bc9f3 Merge remote-tracking branch 'origin/asset-addon' into asset-addon
# Conflicts:
#	supervision/assets/list.py
2023-10-24 15:37:53 +02:00
SkalskiP b6001e389e Update docstring formatting in VideoAssets enum
Updated the docstring comment's format inside the VideoAssets enum in supervision/assets/list.py. The update aligns with PEP 8 E501 error code that requires line too long (>80 characters).

Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-24 16:07:48 +03:00
SkalskiP c529402068 Update docstring formatting in VideoAssets enum
Updated the docstring comment's format inside the VideoAssets enum in supervision/assets/list.py. The update aligns with PEP 8 E501 error code that requires line too long (>80 characters).
2023-10-24 15:05:00 +02:00
SkalskiP 9d68ee6a1e Merge remote-tracking branch 'origin/asset-addon' into asset-addon 2023-10-24 15:04:02 +02:00
SkalskiP 999c12162a Refactor imports in downloader.py
The 'Response' imported module from 'requests' in downloader.py is not needed.
2023-10-24 15:03:54 +02:00
pre-commit-ci[bot] 7d3082c93b fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-24 13:01:25 +00:00
SkalskiP 4cb7400c75 Merge remote-tracking branch 'origin/asset-addon' into asset-addon 2023-10-24 15:01:12 +02:00
SkalskiP 3f5f5fb070 Rename asset_list.py and update VideoAssets enumeration
The file asset_list.py has been renamed to list.py for better readability and simplicity. In the VideoAssets enumeration, additional information has been included. This includes specific details for each member of the enum, notably the filename of the related video and its URL.
2023-10-24 15:01:03 +02:00
pre-commit-ci[bot] 8689c294bf fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-24 12:34:28 +00:00
SkalskiP 3391eec078 Refactor and improve readability of downloader.py
The code for the downloader function in the supervision/assets/downloader.py file has been refactored and optimized. Package imports were cleaned up to remove unnecessary functions and the "path_exists" and "os_remove" functions were replaced with their pathlib equivalents to improve consistency.
2023-10-24 14:31:31 +02:00
SkalskiP 6887b0b412 "Correct md5 hash reference in downloader script
Updated the reference for the md5 hash in downloader.py.
2023-10-24 14:25:11 +02:00
SkalskiP a36abd4297 "Fix reference bug in video asset downloader
Updated 'asset_name' to 'filename' in downloader.py. The downloader was using the incorrect variable 'asset_name', causing failed video asset downloads. Correcting to 'filename' allows for accurate md5 check and download."
2023-10-24 14:21:58 +02:00
SkalskiP 7715ef2a17 The downloader was incorrectly using 'asset_name' instead of 'filename' leading to missed video asset downloads. The reference has been corrected to use 'filename' for proper checking and downloading. 2023-10-24 14:16:46 +02:00
SkalskiP 9b3dc37e28 Merge remote-tracking branch 'origin/asset-addon' into asset-addon 2023-10-24 14:14:26 +02:00
SkalskiP 24aefe6bcd Fix asset name checking in downloader module 2023-10-24 14:12:45 +02:00
pre-commit-ci[bot] 52452c019c fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-24 12:04:33 +00:00
SkalskiP dca6d1248f Merge remote-tracking branch 'origin/asset-addon' into asset-addon 2023-10-24 14:04:11 +02:00
SkalskiP 03fd015f39 Improve readability and maintainability in downloader.py 2023-10-24 14:04:00 +02:00
pre-commit-ci[bot] 7faddb52ca fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-24 11:23:24 +00:00
SkalskiP f987e4f786 Refactor video assets enum and variable names
Renamed enum and variables to improve clarity for VideoAssets in asset_list.py. For instance, MILK_1 is updated to MILK_BOTTLED_PLANT and PEOPLE_WALKING_BW to PEOPLE_WALKING. Also, the VIDEO_ASSETS dictionary type hint updated to Dict. Additionally, a new method 'list' added to class VideoAssets that returns a list of all enum values.
2023-10-24 13:23:05 +02:00
Onuralp SEZER a00a752d44 Merge pull request #522 from roboflow/pre-commit-ci-update-config
chore(pre_commit): ⬆ pre_commit autoupdate
2023-10-23 20:55:12 +03:00
pre-commit-ci[bot] 8bf721559f chore(pre_commit): ⬆ pre_commit autoupdate
updates:
- [github.com/psf/black: 23.9.1 → 23.10.0](https://github.com/psf/black/compare/23.9.1...23.10.0)
- [github.com/astral-sh/ruff-pre-commit: v0.0.292 → v0.1.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.292...v0.1.1)
2023-10-23 17:44:59 +00:00
abhishek7kalra 9f901bb61e Fixed position argument logic in TraceAnnotator 2023-10-21 18:16:58 +05:30
Abhishek Kalra ece7164ce6 Merge branch 'roboflow:develop' into develop 2023-10-21 16:34:04 +05:30
Piotr Skalski de45e9d67f Merge pull request #510 from roboflow/509-mask-annotator-from-sam-error
fix(notebook): 🐛📘 sam detection ColorLookup param and enum added and sv version updated
2023-10-21 12:28:12 +02:00
Onuralp SEZER b815c0e7fc fix(notebook): 🐛📘 sam detection ColorLookup param and enum added and sv version updated
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-21 10:36:30 +03:00
Piotr Skalski c158f96b75 Merge pull request #502 from roboflow/main
Merge pull request #493 from roboflow/develop
2023-10-19 12:39:55 +02:00
Piotr Skalski f34993c202 Merge pull request #493 from roboflow/develop
`supervision-0.16.0` release
2023-10-19 10:23:59 +02:00
SkalskiP f44a9376ec Update version number in pyproject.toml
Updated the version number in pyproject.toml from 0.16.0rc3 to 0.16.0. This denotes the transition from the release candidate to the official version.
2023-10-19 10:22:38 +02:00
Piotr Skalski 48752b432b Merge pull request #501 from roboflow/feature/0.16.0-changelog
Remove custom 404 page and update documentation for new release
2023-10-19 00:44:16 +02:00
pre-commit-ci[bot] c1797ffd81 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 22:42:55 +00:00
SkalskiP a640e527d0 Remove custom 404 page and update documentation for new release
The custom 404.html was removed as it was no longer necessary with the updates to the Mkdocs.yml file. Upgraded the project version from 0.16.0rc2 to 0.16.0rc3 in the pyproject.toml file. Various updates were added to the changelog.md to reflect improvements and bug fixes in the new project release. This includes new annotations, utility improvements, and bug-fixes to improve project functionality.
2023-10-19 00:41:13 +02:00
Piotr Skalski d894c7814b Merge pull request #499 from roboflow/feature/add_draw_image_docs
Add new drawing methods and improve type hints
2023-10-18 23:13:06 +02:00
pre-commit-ci[bot] 815c43beb8 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 21:11:27 +00:00
SkalskiP 2fed8ae0c3 test 2023-10-18 23:10:36 +02:00
pre-commit-ci[bot] 586ff5b3fb fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 20:59:14 +00:00
SkalskiP 8b73c12bcc test 2023-10-18 22:58:58 +02:00
SkalskiP 67d1323daa Merge remote-tracking branch 'origin/feature/add_draw_image_docs' into feature/add_draw_image_docs
# Conflicts:
#	supervision/draw/utils.py
2023-10-18 22:56:20 +02:00
SkalskiP 0e6d69cf85 test 2023-10-18 22:56:09 +02:00
pre-commit-ci[bot] a5c211ff61 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 20:54:16 +00:00
SkalskiP 5f5b4da845 Merge remote-tracking branch 'origin/feature/add_draw_image_docs' into feature/add_draw_image_docs
# Conflicts:
#	supervision/draw/utils.py
2023-10-18 22:53:22 +02:00
SkalskiP be16b84340 test 2023-10-18 22:53:10 +02:00
pre-commit-ci[bot] 08af18ad41 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 20:49:57 +00:00
SkalskiP caf504c0c9 Merge remote-tracking branch 'origin/feature/add_draw_image_docs' into feature/add_draw_image_docs 2023-10-18 22:49:44 +02:00
SkalskiP 893a19a991 test 2023-10-18 22:49:35 +02:00
pre-commit-ci[bot] b35a6161dd fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 20:46:25 +00:00
SkalskiP aabca4a4b5 Merge remote-tracking branch 'origin/feature/add_draw_image_docs' into feature/add_draw_image_docs 2023-10-18 22:46:10 +02:00
SkalskiP 57ba059f1c test 2023-10-18 22:45:58 +02:00
pre-commit-ci[bot] 743f3281a5 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 20:33:06 +00:00
SkalskiP 737cb37249 Add new drawing methods and improve type hints
Expanded the drawing functionality by adding new utility methods 'draw_image', 'draw_line' and 'draw_rectangle' and imported them in supervision/__init__.py. Updated the documentation of draw/utils, to include 'draw_image'. Improved type hinting in draw/color.py and draw/utils.py. Also, some redundant comments and unnecessary immediate memory freeing line are removed from draw/utils.py to enhance code readability.
2023-10-18 22:31:34 +02:00
Piotr Skalski 78a4e73f25 Merge pull request #449 from mario-dg/watermark_images_videos
feat: 🚀 Enable Watermarking images and videos
2023-10-18 22:23:25 +02:00
Piotr Skalski dc9c1151c5 Merge pull request #498 from roboflow/feature/heat_map_docs_update
Add HeatMapAnnotator class to supervision
2023-10-18 21:38:00 +02:00
SkalskiP 5f82aac9e6 Update example images link in core.py and annotators.md
The hyperlink to images in the example blocks in `supervision/annotators/core.py`, and `docs/annotators.md` was modified to reflect recent updates to the annotated heat map image.
2023-10-18 21:34:56 +02:00
SkalskiP d66a539779 Update example code blocks in core.py and annotators.md
Code examples in `supervision/annotators/core.py` and `docs/annotators.md` have been updated for clarity and consistency. The changes include renaming variables more appropriately and elaborating on the video processing steps which now includes tracking and annotating frames using a YOLO model. This revision aims to make examples more understandable and consistent for users following the documentation.
2023-10-18 21:25:44 +02:00
SkalskiP a037a4a404 Add HeatMapAnnotator class to supervision
A HeatMapAnnotator class has been added for visualization purposes. This class can be used to draw heatmaps on an image based on provided detections, where the heat accumulates over time and is drawn as a semi-transparent overlay of blurred circles.
2023-10-18 21:17:51 +02:00
Piotr Skalski 871968a916 Merge pull request #466 from kapter/addHeatmapAnnotator
New feature HeatmapAnnotator
2023-10-18 20:59:53 +02:00
Piotr Skalski 5ca30f5898 Merge pull request #489 from roboflow/add-new-docs
Add How to Detect and Annotate guide
2023-10-18 20:55:03 +02:00
pre-commit-ci[bot] 54bb79c220 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 18:51:33 +00:00
SkalskiP 809d8946e6 Update docs on object detection and annotation
This commit clarifies the process of object detection and annotation using Supervision and the Ultralytics YOLOv8 model. The changes also include updated instructions on how to load model predictions into Supervision and using them to annotate images, with links to the methods used in the process and the available options. An image showing the resulting annotated image has also been added for better understanding. The changes are shaped to make the documentation more informative, concise, and easy to follow.
2023-10-18 20:50:52 +02:00
Piotr Skalski e2305e6f57 Merge pull request #496 from roboflow/feature/dot_annotator_docs_update
Expand and update `Color`, `ColorPalette`, and `DotAnnotator` classes
2023-10-18 19:05:07 +02:00
SkalskiP e173510117 Refactor DotAnnotator docstring for clarity 2023-10-18 19:01:54 +02:00
pre-commit-ci[bot] e209c7436c fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 16:57:05 +00:00
SkalskiP 25a45aa423 Expand and update Color, ColorPalette, and DotAnnotator classes
Added detailed comments and examples to the Color and ColorPalette classes in supervision/draw/color.py, in addition to the DotAnnotator class in supervision/annotators/core.py. The changes clarify the usage and function of these classes. Also appended to the documentation by creating a new section for Color in docs/draw/color.md and including Color and DotAnnotator in docs/annotators.md. Incorporated the new documentation into the navigation structure in mkdocs.yml for user accessibility. The improvements enhance overall code-readability and understandability.
2023-10-18 18:53:39 +02:00
pre-commit-ci[bot] b9d1d78f31 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 16:45:51 +00:00
kapter 142fe02959 add params for hsv 2023-10-18 19:44:15 +03:00
Piotr Skalski 6815814aec Merge pull request #492 from PankajKrana/Create_sv.DotMarkerAnnotator_#396
Create sv.dot marker annotator #396
2023-10-18 18:16:12 +02:00
pre-commit-ci[bot] 1b6613d4a3 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 16:09:41 +00:00
SkalskiP fabfe0783a Refactor DotMarkerAnnotator and merge into core annotators
The DotMarkerAnnotator class has been refactored and named DotAnnotator for simplicity. It's now part of the core annotators to conform with the project structure. The color lookup on the DotAnnotator now uses the 'color_lookup' parameter, allowing for more flexibility and customization in the colors used for the annotations. All the changes aim to standardize the way different annotators are organized and make color customization easier.
2023-10-18 18:09:13 +02:00
Piotr Skalski 2c4e7589b0 Merge pull request #477 from roboflow/poetry-install-docs-fix
docs(fix): 📓 poetry env typo fix
2023-10-18 16:34:59 +02:00
Piotr Skalski 0abe36e079 Merge pull request #490 from roboflow/feature/update_line_zone
Add documentation and improvements to "LineZone" functionality
2023-10-18 16:15:38 +02:00
pre-commit-ci[bot] 61809f9329 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 13:53:26 +00:00
Pankaj Kumar Rana 69f3d10e42 Merge branch 'roboflow:develop' into Create_sv.DotMarkerAnnotator_#396 2023-10-18 19:13:40 +05:30
pre-commit-ci[bot] 62c45548a6 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 12:44:20 +00:00
SkalskiP 00e209744f Add documentation and improvements to "LineZone" functionality
Descriptions for various attributes and functionalities have been added into LineZone class to aid developers in understanding their behaviour. Also, the trigger function was modified to return two separate boolean arrays - 'crossed_in' and 'crossed_out' to denote objects crossing the line in specific directions. Moreover, Line Zone documentation is added to the side navigation in mkdocs.yml.
2023-10-18 14:42:59 +02:00
James Gallagher 8dcfb42751 add data loader link 2023-10-18 13:13:09 +01:00
James Gallagher a5a853e141 resolve conflict 2023-10-18 13:11:29 +01:00
Piotr Skalski 034c2bd9a8 Merge pull request #482 from abhishek7kalra/linezonetrigger
Linezone.trigger returns bool nparray
2023-10-18 13:48:00 +02:00
Piotr Skalski a7449ba56f Update README.md 2023-10-18 12:42:26 +02:00
Onuralp SEZER 8f302c0646 Merge pull request #488 from roboflow/dependabot/pip/urllib3-2.0.7
Bump urllib3 from 2.0.6 to 2.0.7
2023-10-18 12:26:39 +03:00
pre-commit-ci[bot] 1ddb78b662 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-18 09:22:43 +00:00
James Gallagher db4afe9885 add how to detect and annotate guide 2023-10-18 10:20:42 +01:00
dependabot[bot] 72a780b74a Bump urllib3 from 2.0.6 to 2.0.7
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.0.6...2.0.7)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-17 21:06:21 +00:00
PankajKrana b2e9a668b2 Create sv.DotMarkerAnnotator #396 2023-10-17 01:48:54 +05:30
Piotr Skalski 57ef24bcb3 Merge pull request #485 from roboflow/domain-change
Change domain to supervision.roboflow.com in mkdocs
2023-10-16 14:13:19 +02:00
James Gallagher eda6909c91 change domain to supervision.roboflow.com in mkdocs 2023-10-16 13:10:52 +01:00
Piotr Skalski 9a9bf62fe0 Merge pull request #484 from roboflow/404-fix
Add `/` to mkdocs site_url
2023-10-16 14:09:49 +02:00
James Gallagher 1ab50cdb3c add / to mkdocs site_url 2023-10-16 13:06:43 +01:00
Onuralp SEZER f78c282b7e Add 404 page - PR #483 from roboflow/add-404 2023-10-16 11:13:26 +03:00
pre-commit-ci[bot] 3d843d710d fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-16 08:04:17 +00:00
James Gallagher 75db51aa90 add 404 page 2023-10-16 09:00:12 +01:00
Abhishek Kalra e927a3c0a5 Merge pull request #2 from abhishek7kalra/linezonetrigger
change return type from list to nparray
2023-10-15 19:07:54 +05:30
abhishek7kalra fe8a8260dc change return type from list to nparray 2023-10-15 19:06:18 +05:30
Abhishek Kalra b1f85969a5 Merge pull request #1 from abhishek7kalra/linezonetrigger
Linezonetrigger
2023-10-15 18:12:42 +05:30
abhishek7kalra bf725ef0f7 fix pre-commit 2023-10-15 18:10:54 +05:30
abhishek7kalra 338c589032 LineZone.trigger update to return info 2023-10-15 17:42:40 +05:30
Onuralp SEZER f3b92163ad ci(dependabot): ⬆️ create dependabot.yml config for update github actions and python packages automatically 2023-10-14 18:08:46 +03:00
Rajarshi Misra e71232f6ff Merge branch 'roboflow:develop' into develop 2023-10-14 13:55:55 +05:30
pre-commit-ci[bot] 9e5d30732d fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-13 22:52:48 +00:00
capjamesg 9c2aaa0d2e add classification annotator and from_clip loader 2023-10-13 23:50:18 +01:00
Onuralp SEZER 2ab5941cbc feat(assets): ✨ assets and assets downloader add-on for supervision[assets]
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-14 01:39:25 +03:00
Onuralp SEZER 4baf570b28 docs(fix): 📓 poetry env typo fix 2023-10-14 01:12:16 +03:00
Rajarshi Misra 3dbbcf79ae Final 2023-10-13 22:55:41 +05:30
pre-commit-ci[bot] 47dcb19829 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-13 17:24:29 +00:00
Rajarshi Misra 9c96180a74 Update track_objects.md 2023-10-13 22:53:58 +05:30
Rajarshi Misra cd76b79ec5 Update track_objects.md 2023-10-13 18:51:53 +05:30
pre-commit-ci[bot] 377b3fdda7 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-13 13:17:02 +00:00
Rajarshi Misra 9572469f5f Final changes left 2023-10-13 18:46:49 +05:30
kapter 1324cda600 unnecessary function(get_xy) removed 2023-10-13 16:09:24 +03:00
Piotr Skalski 9ded70c8da Merge pull request #465 from roboflow/feature/annotator-color-lookup-improvements
Update color mapping system in detection annotations
2023-10-13 13:34:43 +02:00
Rajarshi Misra da7c056812 Merge branch 'roboflow:develop' into develop 2023-10-13 15:29:28 +05:30
Piotr Skalski 8cda753334 Merge pull request #469 from roboflow/docs-virtualenv-pip
docs: 📓 development virtualenv installation pip upgrade added
2023-10-13 00:27:19 +02:00
Onuralp SEZER a14159c150 docs: 📓 development virtualenv installation pip upgrade added 2023-10-13 00:56:01 +03:00
pre-commit-ci[bot] ae00a9d65f fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-12 20:48:20 +00:00
kapter c51159b598 added HeatmapAnnotator 2023-10-12 23:44:26 +03:00
Rajarshi Misra b1f207f2ee Update track_objects.md
Added all the subtopics and 'what is tracking'
2023-10-12 22:47:16 +05:30
pre-commit-ci[bot] 476a31fa79 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-12 17:11:59 +00:00
SkalskiP e1e455f99c Update color mapping system in detection annotations
Adjusted the way colors are applied to detection annotations to allow support for custom color schemes. Modified 'ColorMap' to 'ColorLookup' across multiple files, adding ability to use a color lookup array. This refinement will enable users to assign custom colors to different detection annotations, offering greater flexibility in visual representation of detection data. Updated related tests to reflect these changes.
2023-10-12 19:10:19 +02:00
Rajarshi Misra f82f297f2e Update track_objects.md
Typo
2023-10-12 19:58:55 +05:30
Rajarshi Misra 9a2a87a170 Just writing the title 2023-10-12 19:58:11 +05:30
Piotr Skalski 5b5e0eb88d Merge pull request #457 from roboflow/cache-pip
ci: 🚧 github action - python cache added 🚀
2023-10-12 14:32:02 +02:00
Onuralp SEZER d0139f5293 ci: 🚧 clear cache once a month and manual run 🚀
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-12 13:44:03 +03:00
Onuralp SEZER bed7ed45b4 ci: 🚧 python github action cache added 🚀
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-12 12:44:48 +03:00
Piotr Skalski 35142fc755 Merge pull request #456 from roboflow/revert-436-develop
Revert "#418 Make sv.ByteTrack work with segmentation model "
2023-10-12 01:11:14 +02:00
pre-commit-ci[bot] f041f0ddcc fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-11 23:09:07 +00:00
Piotr Skalski 253a136f43 Revert "#418 Make sv.ByteTrack work with segmentation model " 2023-10-12 01:08:35 +02:00
SkalskiP 9cefff8627 Supervision Examples guidelines refactor. 2023-10-11 17:03:37 +02:00
Piotr Skalski f2af290166 Merge pull request #344 from onuralpszr/examples_improvements
Adding example and  example guidelines
2023-10-11 15:06:50 +02:00
Piotr Skalski 988da89bf4 Merge pull request #454 from jayaBalaR/patch-1
Adding HuggingFace Annotators Space link to `README.md`
2023-10-11 12:12:37 +02:00
JAYABALAMBIKA.R b4a8859616 Update README.md
Adding HuggingFace Annotators Space link to README.md
2023-10-11 15:34:17 +05:30
Piotr Skalski 9fff77a6e3 Merge pull request #448 from roboflow/pre-commit-isort-duplicate
chore: 🔥 remove duplicate isort from pre-commit-config
2023-10-10 11:41:45 +02:00
pre-commit-ci[bot] e7f95e0761 chore(pre_commit): ⬆ pre_commit autoupdate (#445)
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-10 11:28:50 +03:00
Onuralp SEZER 2254e59bdf chore: 🔥 remove duplicate isort from pre-commit-config 2023-10-10 11:26:53 +03:00
Mario da Graca 6a0482ded5 Fixed pre-commit issues 2023-10-10 08:24:29 +02:00
SkalskiP 29532db02f Update version number in pyproject.toml
Upgraded project version from "0.16.0rc1" to "0.16.0rc2" in pyproject.toml.
2023-10-09 19:59:55 +02:00
Piotr Skalski 8eb827b31d Merge pull request #437 from ashishdatta/from_roboflow_tracker_id
Update sv.Detections.from_roboflow to extract tracker_id values from inference response
2023-10-09 19:58:50 +02:00
Piotr Skalski 33e43bc92a Merge pull request #444 from roboflow/fix/halo-annotator-docs
Update example images and modify code parameters
2023-10-09 16:24:26 +02:00
SkalskiP 8b5b0a8516 Bump project version in pyproject.toml
The project version has been upgraded from "0.15.0" to "0.16.0rc1" in the pyproject.toml file. This change signifies the start of a new release candidate cycle.
2023-10-09 16:20:16 +02:00
pre-commit-ci[bot] 9a7b4c34ba fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-09 14:17:52 +00:00
SkalskiP b2ab398029 Update example images and modify code parameters 2023-10-09 16:15:35 +02:00
mario-dg 082f248159 feat: 🚀 watermarking images and videos 2023-10-09 15:42:54 +02:00
Piotr Skalski 72463f5f89 Update README.md 2023-10-09 15:31:20 +02:00
Piotr Skalski 83342ca36f Merge pull request #433 from kapter/HaloAnnotator
new feature HaloAnnotator
2023-10-09 14:57:10 +02:00
Piotr Skalski 48851b5ae5 Merge pull request #436 from AntonioConsiglio/develop
#418 Make sv.ByteTrack work with segmentation model
2023-10-09 14:18:31 +02:00
SkalskiP e5894df156 Reorganize documentation structure and reformat code
Moved advanced filtering documentation to `how_to` directory from `quickstart` to make way for more comprehensive starter guide. Reorganized MkDocs configuration accordingly. Formatted some code in `classification/core.py` and `dataset/core.py` for better readability. Added placeholder files in `how_to` for future guides on object detection, video processing, object tracking, model evaluation, and detections filtering.
2023-10-09 13:41:56 +02:00
pre-commit-ci[bot] 49d268c250 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-09 11:13:48 +00:00
Antonio Consiglio a7a7dac216 Merge branch 'develop' of https://github.com/AntonioConsiglio/supervision into develop 2023-10-09 13:13:32 +02:00
Antonio Consiglio 8bca45bde4 style and doc change as requested 2023-10-09 13:13:28 +02:00
Piotr Skalski 282db45c00 Merge pull request #440 from roboflow/removal_makefile
chore: 🔥 delete redundant Makefile because pypi and formatters are automatic.
2023-10-09 12:18:54 +02:00
Onuralp SEZER 1c5006c013 chore: 🔥 delete Makefile, pypi and formatters has been automatic, we don't need this file anymore 2023-10-09 13:12:55 +03:00
SkalskiP 9b4fa8cb89 Remove redundant file
The file was removed because it was no longer needed in the current implementation.
2023-10-09 12:03:18 +02:00
Piotr Skalski 333408d33a Merge pull request #438 from roboflow/remove_old_yolov8
chore!: 🔥 removal from_yolov8 function from classification and detection
2023-10-09 12:00:21 +02:00
SkalskiP 41a19ac4d6 Remove unnecessary empty line in core.py 2023-10-09 11:58:21 +02:00
pre-commit-ci[bot] fe0df11918 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-09 09:52:13 +00:00
SkalskiP 375b5f8f54 Remove deprecated method from_yolov8 in Classification class
The method 'from_yolov8' was deprecated and was scheduled for removal in 0.16.0 release. The users are encouraged to use the more general method 'from_ultralytics' which supports results from any Ultralytics engine.
2023-10-09 11:51:56 +02:00
Onuralp SEZER 18fe2e99de chore!: 🔥 removal from_yolov8
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-08 19:52:33 +03:00
pre-commit-ci[bot] a83d3b4c7e fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-07 20:12:29 +00:00
kapter 89c9f88aeb add kernel size var and change method of overlay 2023-10-07 23:12:11 +03:00
ashishdatta 6ef7bf31d3 formatting 2023-10-07 10:32:25 -07:00
ashishdatta c3a025cc9d Extending testing to support tracker_id field.
Cases covered:
empty
non-empty without tracker_id key
non-empty with tracker_id key and None value
non-empty with tracker_id key and non-None value
2023-10-07 10:27:40 -07:00
ashishdatta f489f944b8 Extending from_roboflow to support tracker_ids 2023-10-07 10:26:04 -07:00
ashishdatta cfb1e0ea60 Inference module now supports tracking detected objcets, extending process_roboflow_result to support that. 2023-10-07 10:24:26 -07:00
pre-commit-ci[bot] 5efd535e9d fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-07 17:20:31 +00:00
Antonio Consiglio a550aaa812 Merge branch 'develop' of https://github.com/AntonioConsiglio/supervision into develop 2023-10-07 19:15:04 +02:00
Antonio Consiglio 30994243ae Make sv.ByteTrack work with segmentation model#418 2023-10-07 19:15:03 +02:00
pre-commit-ci[bot] 99707582bc fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-07 17:08:17 +00:00
Antonio Consiglio c0b87a6f04 Make sv.ByteTrack work with segmentation model#418 2023-10-07 19:03:30 +02:00
Piotr Skalski d30d80717c Merge pull request #422 from hardikdava/box_mask_annotator
Added box mask annotators
2023-10-07 00:47:09 +02:00
Piotr Skalski 4733ebe27d Merge pull request #432 from roboflow/fix/fps_monitor_docs
Move FpsMonitor from utils to video module
2023-10-07 00:35:06 +02:00
pre-commit-ci[bot] 44e4eeaa69 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-06 22:33:32 +00:00
pre-commit-ci[bot] 2952286f95 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-06 22:25:02 +00:00
SkalskiP c5e1211c74 Move FpsMonitor from utils to video module
This commit relocates the FpsMonitor class from the utils module to the video module.
2023-10-07 00:24:20 +02:00
kapter 72dc07e332 added HaloAnnotator 2023-10-07 01:11:49 +03:00
Piotr Skalski c5c37e4a6c Merge pull request #430 from akashpambhar/fix-return-empty-detections
Fix return value when sv.Detections is empty
2023-10-07 00:04:04 +02:00
Piotr Skalski 8000043bc8 Update supervision/tracker/byte_tracker/core.py 2023-10-07 00:01:24 +02:00
Akash Pambhar 14d0189e2c Fix return value when sv.Detections is empty 2023-10-07 00:51:08 +05:30
Hardik Dava 68a761349d Merge pull request #411 from roboflow/add-colormap-to-init
fix(import): 🐞 add ColorMap into init.py
2023-10-06 21:19:29 +02:00
Onuralp SEZER d5d5725cea Merge pull request #280 from hardikdava/feature/fps
Feature FPS meaure
2023-10-06 22:18:05 +03:00
pre-commit-ci[bot] 669c0658fe fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-06 18:54:41 +00:00
SkalskiP bed28e3db4 Improve the documentation for annotators class 2023-10-06 20:54:09 +02:00
pre-commit-ci[bot] cc93bba741 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-06 18:52:00 +00:00
SkalskiP e7c242bdd4 Update annotators in docs and code 2023-10-06 20:51:31 +02:00
SkalskiP 89c1b63979 Optimize color assignment in mask annotation 2023-10-06 19:24:10 +02:00
Piotr Skalski 456655c2a4 Merge pull request #426 from kapter/Make-MaskAnnotator-faster
faster sv.MaskAnnotator
2023-10-06 18:15:37 +02:00
Piotr Skalski f67a67bd7c Merge pull request #425 from roboflow/discord-button
Add Discord button to README
2023-10-06 11:56:00 +02:00
James Gallagher 30687609f5 update button 2023-10-06 09:51:56 +01:00
Piotr Skalski ab1b2d6d80 🎃 Add hacktoberfest banner to README.md 2023-10-06 10:41:56 +02:00
pre-commit-ci[bot] 5c6323bed0 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-06 08:00:00 +00:00
kapter d2fe2ad40c 10 percent speed up and no ver 2023-10-06 10:58:43 +03:00
pre-commit-ci[bot] 5aaa15c894 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-05 23:13:12 +00:00
kapter 4bb62f06ff add ma ver 2023-10-06 01:51:19 +03:00
kapter 4e7a763ad9 faster maskannotator 2023-10-06 01:22:08 +03:00
James cb225b26e8 Update README.md 2023-10-05 19:01:19 +01:00
Keshav Subramanianandkeshav278 07ec604102 add #a351fb as first default color into sv.draw.color.ColorPalette (#424)
Co-authored-by: keshav278 <vkeshav278@gmail.com>
2023-10-05 20:04:48 +03:00
Hardik Dava ef43640c88 Added box mask annotators 2023-10-05 17:56:32 +02:00
Piotr Skalski 77c126e421 Merge pull request #416 from roboflow/notebook-fixes
Supervision demo notebook fix and yolo-nas fix
2023-10-05 15:18:13 +02:00
Onuralp SEZER edd8b8f41e fix(formatter): 🐛 exclude ipynb for pretty-format-json formatter
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-05 15:36:13 +03:00
Onuralp SEZER cad38104e0 fix(notebook): 🐛📘 sam detection and sv version update
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-05 15:23:47 +03:00
Onuralp SEZER 618fadae2a fix(detection): 🐞 yolo-nas detection check fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-05 15:22:45 +03:00
Piotr Skalski 71d23619b0 Merge pull request #412 from roboflow/main
Merge pull request #404 from roboflow/develop
2023-10-05 09:24:56 +02:00
Onuralp SEZER a57176568a fix(import): 🐞 add ColorMap into init.py
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-05 01:10:26 +03:00
Hardik Dava b482784403 Merge branch 'develop' into feature/fps 2023-10-03 17:57:53 +02:00
Hardik Dava 3b00e04101 Merge remote-tracking branch 'origin/develop' into feature/fps 2023-10-03 17:53:52 +02:00
Onuralp SEZER 227615b766 fix: 🐛 exclude examples folder from package
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-08-31 20:08:29 +03:00
Onuralp SEZER baff75332f docs: 📝 example guide visual rules and license rule added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-08-31 20:03:02 +03:00
Onuralp SEZER 434a695324 docs: 📝 example guidelines added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-08-31 19:54:08 +03:00
Hardik Dava 5d71ab2961 Make with black again 2023-08-11 14:18:25 +02:00
Hardik Dava 5c9e529743 Make with isort 2023-08-11 14:15:47 +02:00
Hardik Dava 3f7043e780 Make with Black 2023-08-11 14:13:17 +02:00
Hardik Dava c746a7f9e4 docs added 2023-08-11 14:08:52 +02:00
Hardik Dava 04629cd7f4 initial commit 2023-08-11 14:07:14 +02:00
122 changed files with 11464 additions and 4253 deletions
+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")
+9 -2
View File
@@ -6,14 +6,21 @@ on:
- master
- main
- develop
permissions:
contents: write
pages: write
pull-requests: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- run: pip install mkdocs-material
- run: pip install "mkdocstrings[python]"
- run: pip install "mkdocs-material[imaging]"
- run: mkdocs gh-deploy --force
+2 -2
View File
@@ -16,10 +16,10 @@ jobs:
steps:
- name: Checkout source
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: 🐍 Set up Python 3.8 environment for build
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.8"
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
python-version: [3.8]
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 }}
+57
View File
@@ -0,0 +1,57 @@
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 \
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."
+21
View File
@@ -135,3 +135,24 @@ dmypy.json
# 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-*
+9 -34
View File
@@ -7,74 +7,49 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: test/.*\.py
- id: check-yaml
exclude: mkdocs.yml
- id: check-docstring-first
- 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
exclude: demo.ipynb
args: ['--autofix', '--no-sort-keys', '--indent=4']
- 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/isort
rev: 5.12.0
hooks:
- id: isort
name: Sort imports
- 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.6'
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.1.14
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
types_or: [ python, pyi, jupyter ]
+2 -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,7 +108,7 @@ 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/).
-22
View File
@@ -1,22 +0,0 @@
.PHONY: style check_code_quality
export PYTHONPATH = .
check_dirs := supervision
style:
black $(check_dirs)
isort --profile black $(check_dirs)
check_code_quality:
black --check $(check_dirs)
isort --check-only --profile black $(check_dirs)
# stop the build if there are Python syntax errors or undefined names
flake8 $(check_dirs) --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. E203 for black, E501 for docstring, W503 for line breaks before logical operators
flake8 $(check_dirs) --count --max-line-length=88 --exit-zero --ignore=D --extend-ignore=E203,E501,W503 --statistics
publish:
poetry build
twine upload -r testpypi dist/* -u ${PYPI_USERNAME} -p ${PYPI_TEST_PASSWORD} --verbose
twine check dist/*
twine upload dist/* -u ${PYPI_USERNAME} -p ${PYPI_PASSWORD} --verbose
+152 -205
View File
@@ -10,15 +10,17 @@
<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) | [collect](https://github.com/roboflow/roboflow-collect)
<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)
[![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)
</div>
@@ -29,265 +31,203 @@
## 💻 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/).
## 🔥 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/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/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/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
@@ -297,6 +237,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.
@@ -305,6 +247,12 @@ Visit our [documentation](https://roboflow.github.io/supervision) page to learn
We love your input! Please see our [contributing guide](https://github.com/roboflow/supervision/blob/main/CONTRIBUTING.md) to get started. Thank you 🙏 to all our contributors!
<p align="center">
<a href="https://github.com/roboflow/supervision/graphs/contributors">
<img src="https://contrib.rocks/image?repo=roboflow/supervision" />
</a>
</p>
<br>
<div align="center">
@@ -352,5 +300,4 @@ We love your input! Please see our [contributing guide](https://github.com/robof
</a>
</a>
</div>
</div>
Vendored
+1340 -1322
View File
File diff suppressed because one or more lines are too long
+349 -93
View File
@@ -1,168 +1,380 @@
---
comments: true
status: new
---
=== "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>
![bounding-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/bounding-box-annotator-example.png){ align=center width="800" }
![bounding-box-annotator-example](https://media.roboflow.com/supervision-annotator-examples/bounding-box-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Mask"
=== "RoundBox"
```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
... )
round_box_annotator = sv.RoundBoxAnnotator()
annotated_frame = round_box_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example.png){ align=center width="800" }
</div>
=== "Ellipse"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> ellipse_annotator = sv.EllipseAnnotator()
>>> annotated_frame = ellipse_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
<div class="result" markdown>
![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ellipse-annotator-example.png){ align=center width="800" }
![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>
![box-corner-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-corner-annotator-example.png){ align=center width="800" }
![box-corner-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-corner-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Color"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
color_annotator = sv.ColorAnnotator()
annotated_frame = color_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![box-mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-mask-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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>
![circle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/circle-annotator-example.png){ align=center width="800" }
![circle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/circle-annotator-example-purple.png){ align=center width="800" }
</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
image = ...
detections = sv.Detections(...)
ellipse_annotator = sv.EllipseAnnotator()
annotated_frame = ellipse_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ellipse-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Halo"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
halo_annotator = sv.HaloAnnotator()
annotated_frame = halo_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![halo-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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
image = ...
detections = sv.Detections(...)
mask_annotator = sv.MaskAnnotator()
annotated_frame = mask_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Polygon"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
polygon_annotator = sv.PolygonAnnotator()
annotated_frame = polygon_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![polygon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/polygon-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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
... )
label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
annotated_frame = label_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-2.png){ align=center width="800" }
![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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>
![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-2.png){ align=center width="800" }
![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Pixelate"
```python
import supervision as sv
image = ...
detections = sv.Detections(...)
pixelate_annotator = sv.PixelateAnnotator()
annotated_frame = pixelate_annotator.annotate(
scene=image.copy(),
detections=detections
)
```
<div class="result" markdown>
![pixelate-annotator-example](https://media.roboflow.com/supervision-annotator-examples/pixelate-annotator-example-10.png){ align=center width="800" }
</div>
=== "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>
![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example.png){ align=center width="800" }
![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example-purple.png){ align=center width="800" }
</div>
=== "HeatMap"
```python
import supervision as sv
from ultralytics import YOLO
model = YOLO('yolov8x.pt')
heat_map_annotator = sv.HeatMapAnnotator()
video_info = sv.VideoInfo.from_video_path(video_path='...')
frames_generator = 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>
@@ -170,30 +382,74 @@
:::supervision.annotators.core.BoundingBoxAnnotator
## MaskAnnotator
## RoundBoxAnnotator
:::supervision.annotators.core.MaskAnnotator
## EllipseAnnotator
:::supervision.annotators.core.EllipseAnnotator
:::supervision.annotators.core.RoundBoxAnnotator
## BoxCornerAnnotator
:::supervision.annotators.core.BoxCornerAnnotator
## OrientedBoxAnnotator
:::supervision.annotators.core.OrientedBoxAnnotator
## ColorAnnotator
:::supervision.annotators.core.ColorAnnotator
## CircleAnnotator
:::supervision.annotators.core.CircleAnnotator
## DotAnnotator
:::supervision.annotators.core.DotAnnotator
## TriangleAnnotator
:::supervision.annotators.core.TriangleAnnotator
## EllipseAnnotator
:::supervision.annotators.core.EllipseAnnotator
## HaloAnnotator
:::supervision.annotators.core.HaloAnnotator
## PercentageBarAnnotator
:::supervision.annotators.core.PercentageBarAnnotator
## HeatMapAnnotator
:::supervision.annotators.core.HeatMapAnnotator
## MaskAnnotator
:::supervision.annotators.core.MaskAnnotator
## PolygonAnnotator
:::supervision.annotators.core.PolygonAnnotator
## LabelAnnotator
:::supervision.annotators.core.LabelAnnotator
## BlurAnnotator
:::supervision.annotators.core.BlurAnnotator
## PixelateAnnotator
:::supervision.annotators.core.PixelateAnnotator
## TraceAnnotator
:::supervision.annotators.core.TraceAnnotator
## BlurAnnotator
## ColorLookup
:::supervision.annotators.core.BlurAnnotator
:::supervision.annotators.utils.ColorLookup
+25
View File
@@ -0,0 +1,25 @@
---
comments: true
---
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]
```
## download_assets
:::supervision.assets.downloader.download_assets
## VideoAssets
:::supervision.assets.list.VideoAssets
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+169
View File
@@ -1,3 +1,172 @@
### 0.18.0 <small>January 25, 2024</small>
- Added [#633](https://github.com/roboflow/supervision/pull/720): [`sv.PercentageBarAnnotator`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#roundboxannotator) allowing to annotate images and videos with rounded corners bounding boxes.
- Added [#770](https://github.com/roboflow/supervision/pull/770): [`sv.OrientedBoxAnnotator`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/draw/color/#color)'s and [`sv.ColorPalette`](https://supervision.roboflow.com/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`).
!!! warning
`sv.ColorPalette.default()` is deprecated and will be removed in `supervision-0.21.0`. Use `sv.ColorPalette.DEFAULT` instead.
- Changed [#769](https://github.com/roboflow/supervision/pull/769): [`sv.ColorPalette.DEFAULT`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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).
!!! warning
`Detections.from_roboflow()` is deprecated and will be removed in `supervision-0.21.0`. Use `Detections.from_inference` instead.
- Fixed [#735](https://github.com/roboflow/supervision/pull/735): [`sv.LineZone`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.PixelateAnnotator) allowing to pixelate objects on images and videos.
- Added [#652](https://github.com/roboflow/supervision/pull/652): [`sv.TriangleAnnotator`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/detection/utils/#supervision.detection.utils.scale_boxes) allowing to scale [`sv.Detections.xyxy`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections) values.
- Added [#637](https://github.com/roboflow/supervision/pull/637): [`sv.calculate_dynamic_text_scale`](https://supervision.roboflow.com/draw/utils/#supervision.draw.utils.calculate_dynamic_text_scale) and [`sv.calculate_dynamic_line_thickness`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.ColorAnnotator).
- Changed [#606](https://github.com/roboflow/supervision/pull/606): [`sv.MaskAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.MaskAnnotator) to make it **5x faster**.
- Fixed [#584](https://github.com/roboflow/supervision/pull/584): [`sv.DetectionDataset.from_yolo`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BlurAnnotator) to trim negative coordinates before bluring detections.
- Fixed [#511](https://github.com/roboflow/supervision/pull/511): [`sv.TraceAnnotator`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.HeatMapAnnotator) allowing to annotate videos with heat maps.
- Added [#492](https://github.com/roboflow/supervision/pull/492): [`sv.DotAnnotator`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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.tigger`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/trackers/#supervision.tracker.byte_tracker.core.ByteTrack) to return `np.array([], dtype=int)` when `svDetections` is empty.
!!! warning
`sv.Detections.from_yolov8` and `sv.Classifications.from_yolov8` as those are now replaced by [`sv.Detections.from_ultralytics`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_ultralytics) and [`sv.Classifications.from_ultralytics`](https://supervision.roboflow.com/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.
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## Classifications
:::supervision.classification.core.Classifications
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
!!! warning
Dataset API is still fluid and may change. If you use Dataset API in your project until further notice, freeze the
+5
View File
@@ -1,3 +1,8 @@
---
comments: true
status: new
---
## Detections
:::supervision.detection.core.Detections
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## InferenceSlicer
:::supervision.detection.tools.inference_slicer.InferenceSlicer
+7
View File
@@ -0,0 +1,7 @@
---
comments: true
---
## LineZone
:::supervision.detection.line_counter.LineZone
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## PolygonZone
:::supervision.detection.tools.polygon_zone.PolygonZone
+8
View File
@@ -0,0 +1,8 @@
---
comments: true
status: new
---
## Detection Smoother
:::supervision.detection.tools.smoother.DetectionsSmoother
+12
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## box_iou_batch
:::supervision.detection.utils.box_iou_batch
@@ -25,3 +29,11 @@
## filter_polygons_by_area
:::supervision.detection.utils.filter_polygons_by_area
## move_boxes
:::supervision.detection.utils.move_boxes
## scale_boxes
:::supervision.detection.utils.scale_boxes
+11
View File
@@ -0,0 +1,11 @@
---
comments: true
---
## Color
:::supervision.draw.color.Color
## ColorPalette
:::supervision.draw.color.ColorPalette
+16
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## draw_line
:::supervision.draw.utils.draw_line
@@ -17,3 +21,15 @@
## draw_text
:::supervision.draw.utils.draw_text
## draw_image
:::supervision.draw.utils.draw_image
## calculate_dynamic_font_scale
:::supervision.draw.utils.calculate_dynamic_text_scale
## calculate_dynamic_line_thickness
:::supervision.draw.utils.calculate_dynamic_line_thickness
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## Position
:::supervision.geometry.core.Position
+143
View File
@@ -0,0 +1,143 @@
---
comments: true
---
Supervision offers a streamlined solution to effortlessly annotate predictions from a
range of object detection and segmentation models. This guide demonstrates how to
execute inference using the YOLOv8 model with either the
[Inference](https://github.com/roboflow/inference) or
[Ultralytics](https://github.com/ultralytics/ultralytics) packages. Following this,
you'll learn how to import these predictions into Supervision for image annotation
purposes.
## Run Inference
First, you'll need to obtain predictions from your object detection or segmentation model.
=== "Ultralytics"
```python
import cv2
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
image = cv2.imread(<PATH TO IMAGE>)
results = model(image)[0]
```
=== "Inference"
```python
import cv2
from inference.models.utils import get_roboflow_model
model = get_roboflow_model(model_id="yolov8n-640", api_key=<ROBOFLOW API KEY>)
image = cv2.imread(<PATH TO IMAGE>)
results = model.infer(image)[0]
```
## Load Predictions into Supervision
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`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_ultralytics) method, which accepts model results from both detection and segmentation models.
```python
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)
```
=== "Inference"
We can do so using the [`sv.Detections.from_inference`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_inference) method, which accepts model results from both detection and segmentation models.
```python
import cv2
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>
image = cv2.imread(<PATH TO IMAGE>)
results = model.infer(image)[0]
detections = sv.Detections.from_inference(results)
```
You can conveniently load predictions from other computer vision frameworks and libraries using:
- [`from_deepsparse`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_deepsparse) ([Deepsparse](https://github.com/neuralmagic/deepsparse))
- [`from_detectron2`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_detectron2) ([Detectron2](https://github.com/facebookresearch/detectron2))
- [`from_mmdetection`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_mmdetection) ([MMDetection](https://github.com/open-mmlab/mmdetection))
- [`from_inference`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_inference) ([Roboflow Inference](https://github.com/roboflow/inference))
- [`from_sam`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_sam) ([Segment Anything Model](https://github.com/facebookresearch/segment-anything))
- [`from_transformers`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_transformers) ([HuggingFace Transformers](https://github.com/huggingface/transformers))
- [`from_yolo_nas`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BoundingBoxAnnotator) and [`sv.LabelAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.LabelAnnotator) classes. If you are running the segmentation model [`sv.MaskAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.MaskAnnotator) is a drop-in replacement for [`sv.BoundingBoxAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BoundingBoxAnnotator) that will allow you to draw masks instead of boxes.
=== "Ultralytics"
```python
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 = [
model.model.names[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)
```
=== "Inference"
```python
import cv2
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>
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)
```
![Predictions plotted on an image](https://media.roboflow.com/supervision_annotate_example.png)
## Display Annotated Image
To display the annotated image in Jupyter Notebook or Google Colab, use the [`sv.plot_image`](https://supervision.roboflow.com/utils/notebook/#supervision.utils.notebook.plot_image) function.
```python
sv.plot_image(annotated_image)
```
@@ -1,5 +1,6 @@
## advanced filtering
---
comments: true
---
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
+317
View File
@@ -0,0 +1,317 @@
---
comments: true
---
Leverage Supervision's advanced capabilities for enhancing your video analysis by
seamlessly [tracking](https://supervision.roboflow.com/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]`](https://supervision.roboflow.com/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](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/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`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.LabelAnnotator)
in Supervision, we can overlay the tracker IDs and class labels on the detected objects,
offering a clear visual representation of each object's class and unique identifier.
=== "Ultralytics"
```{ .py hl_lines="8 15-19 23-24" }
import numpy as np
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
tracker = sv.ByteTrack()
box_annotator = sv.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`](https://supervision.roboflow.com/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.
+49 -3
View File
@@ -1,9 +1,13 @@
---
comments: true
---
<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"
src="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png?updatedAt=1678995927529"
>
</a>
</p>
@@ -13,10 +17,51 @@
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>
## 🚀 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)
- __Track Objects__
---
Discover how to enhance video analysis by implementing seamless object tracking
[:octicons-arrow-right-24: Tutorial](how_to/track_objects)
- > __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>
## 💻 Install
You can install `supervision` with pip in a
[**3.11>=Python>=3.8**](https://www.python.org/) environment.
[**Python>=3.8**](https://www.python.org/) environment.
!!! example "pip install (recommended)"
@@ -46,6 +91,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 +108,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
+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) });
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
!!! warning
Evaluation API is still fluid and may change. If you use Evaluation API in your project until further notice, freeze the
+5
View File
@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% 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>
{% 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 %}
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## ByteTrack
:::supervision.tracker.byte_tracker.core.ByteTrack
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## list_files_with_extensions
:::supervision.utils.file.list_files_with_extensions
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## ImageSink
:::supervision.utils.image.ImageSink
+4
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## plot_image
:::supervision.utils.notebook.plot_image
+8
View File
@@ -1,3 +1,7 @@
---
comments: true
---
## VideoInfo
:::supervision.utils.video.VideoInfo
@@ -6,6 +10,10 @@
:::supervision.utils.video.VideoSink
## FPSMonitor
:::supervision.utils.video.FPSMonitor
## get_video_frames_generator
:::supervision.utils.video.get_video_frames_generator
+31
View File
@@ -0,0 +1,31 @@
## 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)
- [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
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]
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,167 @@
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:
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.18.0rc1
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,145 @@
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:
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()
+92 -11
View File
@@ -1,3 +1,5 @@
# tracking
## 👋 hello
This script provides functionality for processing videos using YOLOv8 for object
@@ -5,16 +7,95 @@ detection and Supervision for tracking and annotation.
## 💻 install
```bash
pip install -r requirements.txt
```
- clone repository and navigate to example directory
## ⚙️ parameters
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/tracking
```
| parameter | required | description |
|:-------------------------|:--------:|:----------------------------------------------------------------------------------|
| `--source_weights_path` | ✓ | Path to the source weights file for YOLOv8. |
| `--source_video_path` | ✓ | Path to the source video file to be processed. |
| `--target_video_path` | ✓ | Path to the target video file (output). |
| `--confidence_threshold` | ✗ | Confidence threshold for YOLO model detection. Default is 0.3. |
| `--iou_threshold` | ✗ | IOU (Intersection over Union) threshold for YOLO model detection. Default is 0.7. |
- 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
- ultralytics
- `--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 to be processed.
This is the video on which object detection and annotation will be performed.
- `--target_video_path`: Required. The path where the processed video, with annotations
added, will be saved. This is your output video file.
- `--confidence_threshold` (optional): Sets the confidence level at which the model
identifies objects in the video. Default is `0.3`. A higher threshold makes the model
more selective, while a lower threshold makes it more inclusive in identifying objects.
- `--iou_threshold` (optional): Specifies the IOU (Intersection Over Union) threshold
for the model, defaulting to `0.7`. This parameter helps in differentiating between
distinct objects, especially in crowded scenes.
- 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"`.
- `--source_video_path`: Required. The path to the source video file to be processed.
This is the video on which object detection and annotation will be performed.
- `--target_video_path`: Required. The path where the processed video, with annotations
added, will be saved. This is your output video file.
- `--confidence_threshold` (optional): Sets the confidence level at which the model
identifies objects in the video. Default is `0.3`. A higher threshold makes the model
more selective, while a lower threshold makes it more inclusive in identifying objects.
- `--iou_threshold` (optional): Specifies the IOU (Intersection Over Union) threshold
for the model, defaulting to `0.7`. This parameter helps in differentiating between
distinct objects, especially in crowded scenes.
## ⚙️ run
- inference
```bash
python inference_example.py \
--roboflow_api_key <ROBOFLOW API KEY> \
--source_video_path input.mp4 \
--target_video_path tracking_result.mp4
```
- ultralytics
```bash
python ultralytics_example.py \
--source_weights_path yolov8s.pt \
--source_video_path input.mp4 \
--target_video_path tracking_result.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.
+101
View File
@@ -0,0 +1,101 @@
import argparse
import os
from inference.models.utils import get_roboflow_model
from tqdm import tqdm
import supervision as sv
def process_video(
roboflow_api_key: str,
model_id: str,
source_video_path: str,
target_video_path: str,
confidence_threshold: float = 0.3,
iou_threshold: float = 0.7,
) -> None:
model = get_roboflow_model(model_id=model_id, api_key=roboflow_api_key)
tracker = sv.ByteTrack()
box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
frame_generator = sv.get_video_frames_generator(source_path=source_video_path)
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
with sv.VideoSink(target_path=target_video_path, video_info=video_info) as sink:
for frame in tqdm(frame_generator, total=video_info.total_frames):
results = model.infer(
frame, confidence=confidence_threshold, iou_threshold=iou_threshold
)[0]
detections = sv.Detections.from_inference(results)
detections = tracker.update_with_detections(detections)
annotated_frame = box_annotator.annotate(
scene=frame.copy(), detections=detections
)
annotated_labeled_frame = label_annotator.annotate(
scene=annotated_frame, detections=detections
)
sink.write_frame(frame=annotated_labeled_frame)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Video Processing with Inference and ByteTrack"
)
parser.add_argument(
"--model_id",
default="yolov8x-1280",
help="Roboflow model ID",
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
)
parser.add_argument(
"--roboflow_api_key",
default=None,
help="Roboflow API key",
type=str,
)
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
process_video(
roboflow_api_key=args.roboflow_api_key,
model_id=args.model_id,
source_video_path=args.source_video_path,
target_video_path=args.target_video_path,
confidence_threshold=args.confidence_threshold,
iou_threshold=args.iou_threshold,
)
+1
View File
@@ -1,3 +1,4 @@
inference
supervision
tqdm
ultralytics
@@ -17,7 +17,7 @@ def process_video(
tracker = sv.ByteTrack()
box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator(classes=model.names)
label_annotator = sv.LabelAnnotator()
frame_generator = sv.get_video_frames_generator(source_path=source_video_path)
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
+8
View File
@@ -1 +1,9 @@
data/
venv/
*.pt
*.pth
*.mp4
*.mov
*.png
*.jpg
*.jpeg
+95 -23
View File
@@ -1,6 +1,10 @@
# traffic analysis
## 👋 hello
This script performs traffic flow 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 tracking, annotations, etc.
This script performs traffic flow 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 tracking, annotations, etc.
https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-60e9c81b3900
@@ -8,37 +12,105 @@ https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-
- clone repository and navigate to example directory
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/traffic_analysis
```
```bash
git clone https://github.com/roboflow/supervision.git
cd supervision/examples/traffic_analysis
```
- setup python environment and activate it [optional]
```bash
python3 -m venv venv
source venv/bin/activate
```
```bash
python3 -m venv venv
source venv/bin/activate
```
- install required dependencies
```bash
pip install -r requirements.txt
```
```bash
pip install -r requirements.txt
```
- download `traffic_analysis.pt` and `traffic_analysis.mov` files
```bash
./setup.sh
```
```bash
./setup.sh
```
## 🛠️ script arguments
- ultralytics
- `--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` (optional): 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.
- 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 `"vehicle-count-in-drone-video/6"`.
- `--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` (optional): 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
```bash
python script.py \
--source_weights_path data/traffic_analysis.pt \
--source_video_path data/traffic_analysis.mov \
--confidence_threshold 0.3 \
--iou_threshold 0.5 \
--target_video_path data/traffic_analysis_result.mov
```
- ultralytics
```bash
python ultralytics_example.py \
--source_weights_path data/traffic_analysis.pt \
--source_video_path data/traffic_analysis.mov \
--confidence_threshold 0.3 \
--iou_threshold 0.5 \
--target_video_path data/traffic_analysis_result.mov
```
- inference
```bash
python inference_example.py \
--roboflow_api_key <ROBOFLOW API KEY> \
--source_video_path data/traffic_analysis.mov \
--confidence_threshold 0.3 \
--iou_threshold 0.5 \
--target_video_path data/traffic_analysis_result.mov
```
## © 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,238 @@
import argparse
import os
from typing import Dict, List, Set, Tuple
import cv2
import numpy as np
from inference.models.utils import get_roboflow_model
from tqdm import tqdm
import supervision as sv
COLORS = sv.ColorPalette.default()
ZONE_IN_POLYGONS = [
np.array([[592, 282], [900, 282], [900, 82], [592, 82]]),
np.array([[950, 860], [1250, 860], [1250, 1060], [950, 1060]]),
np.array([[592, 582], [592, 860], [392, 860], [392, 582]]),
np.array([[1250, 282], [1250, 530], [1450, 530], [1450, 282]]),
]
ZONE_OUT_POLYGONS = [
np.array([[950, 282], [1250, 282], [1250, 82], [950, 82]]),
np.array([[592, 860], [900, 860], [900, 1060], [592, 1060]]),
np.array([[592, 282], [592, 550], [392, 550], [392, 282]]),
np.array([[1250, 860], [1250, 560], [1450, 560], [1450, 860]]),
]
class DetectionsManager:
def __init__(self) -> None:
self.tracker_id_to_zone_id: Dict[int, int] = {}
self.counts: Dict[int, Dict[int, Set[int]]] = {}
def update(
self,
detections_all: sv.Detections,
detections_in_zones: List[sv.Detections],
detections_out_zones: List[sv.Detections],
) -> sv.Detections:
for zone_in_id, detections_in_zone in enumerate(detections_in_zones):
for tracker_id in detections_in_zone.tracker_id:
self.tracker_id_to_zone_id.setdefault(tracker_id, zone_in_id)
for zone_out_id, detections_out_zone in enumerate(detections_out_zones):
for tracker_id in detections_out_zone.tracker_id:
if tracker_id in self.tracker_id_to_zone_id:
zone_in_id = self.tracker_id_to_zone_id[tracker_id]
self.counts.setdefault(zone_out_id, {})
self.counts[zone_out_id].setdefault(zone_in_id, set())
self.counts[zone_out_id][zone_in_id].add(tracker_id)
detections_all.class_id = np.vectorize(
lambda x: self.tracker_id_to_zone_id.get(x, -1)
)(detections_all.tracker_id)
return detections_all[detections_all.class_id != -1]
def initiate_polygon_zones(
polygons: List[np.ndarray],
frame_resolution_wh: Tuple[int, int],
triggering_position: sv.Position = sv.Position.CENTER,
) -> List[sv.PolygonZone]:
return [
sv.PolygonZone(
polygon=polygon,
frame_resolution_wh=frame_resolution_wh,
triggering_position=triggering_position,
)
for polygon in polygons
]
class VideoProcessor:
def __init__(
self,
roboflow_api_key: str,
model_id: str,
source_video_path: str,
target_video_path: str = None,
confidence_threshold: float = 0.3,
iou_threshold: float = 0.7,
) -> None:
self.conf_threshold = confidence_threshold
self.iou_threshold = iou_threshold
self.source_video_path = source_video_path
self.target_video_path = target_video_path
self.model = get_roboflow_model(model_id=model_id, api_key=roboflow_api_key)
self.tracker = sv.ByteTrack()
self.video_info = sv.VideoInfo.from_video_path(source_video_path)
self.zones_in = initiate_polygon_zones(
ZONE_IN_POLYGONS, self.video_info.resolution_wh, sv.Position.CENTER
)
self.zones_out = initiate_polygon_zones(
ZONE_OUT_POLYGONS, self.video_info.resolution_wh, sv.Position.CENTER
)
self.box_annotator = sv.BoxAnnotator(color=COLORS)
self.trace_annotator = sv.TraceAnnotator(
color=COLORS, position=sv.Position.CENTER, trace_length=100, thickness=2
)
self.detections_manager = DetectionsManager()
def process_video(self):
frame_generator = sv.get_video_frames_generator(
source_path=self.source_video_path
)
if self.target_video_path:
with sv.VideoSink(self.target_video_path, self.video_info) as sink:
for frame in tqdm(frame_generator, total=self.video_info.total_frames):
annotated_frame = self.process_frame(frame)
sink.write_frame(annotated_frame)
else:
for frame in tqdm(frame_generator, total=self.video_info.total_frames):
annotated_frame = self.process_frame(frame)
cv2.imshow("Processed Video", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
def annotate_frame(
self, frame: np.ndarray, detections: sv.Detections
) -> np.ndarray:
annotated_frame = frame.copy()
for i, (zone_in, zone_out) in enumerate(zip(self.zones_in, self.zones_out)):
annotated_frame = sv.draw_polygon(
annotated_frame, zone_in.polygon, COLORS.colors[i]
)
annotated_frame = sv.draw_polygon(
annotated_frame, zone_out.polygon, COLORS.colors[i]
)
labels = [f"#{tracker_id}" for tracker_id in detections.tracker_id]
annotated_frame = self.trace_annotator.annotate(annotated_frame, detections)
annotated_frame = self.box_annotator.annotate(
annotated_frame, detections, labels
)
for zone_out_id, zone_out in enumerate(self.zones_out):
zone_center = sv.get_polygon_center(polygon=zone_out.polygon)
if zone_out_id in self.detections_manager.counts:
counts = self.detections_manager.counts[zone_out_id]
for i, zone_in_id in enumerate(counts):
count = len(self.detections_manager.counts[zone_out_id][zone_in_id])
text_anchor = sv.Point(x=zone_center.x, y=zone_center.y + 40 * i)
annotated_frame = sv.draw_text(
scene=annotated_frame,
text=str(count),
text_anchor=text_anchor,
background_color=COLORS.colors[zone_in_id],
)
return annotated_frame
def process_frame(self, frame: np.ndarray) -> np.ndarray:
results = self.model.infer(
frame, confidence=self.conf_threshold, iou_threshold=self.iou_threshold
)[0]
detections = sv.Detections.from_inference(results)
detections.class_id = np.zeros(len(detections))
detections = self.tracker.update_with_detections(detections)
detections_in_zones = []
detections_out_zones = []
for i, (zone_in, zone_out) in enumerate(zip(self.zones_in, self.zones_out)):
detections_in_zone = detections[zone_in.trigger(detections=detections)]
detections_in_zones.append(detections_in_zone)
detections_out_zone = detections[zone_out.trigger(detections=detections)]
detections_out_zones.append(detections_out_zone)
detections = self.detections_manager.update(
detections, detections_in_zones, detections_out_zones
)
return self.annotate_frame(frame, detections)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Traffic Flow Analysis with Inference and ByteTrack"
)
parser.add_argument(
"--model_id",
default="vehicle-count-in-drone-video/6",
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
processor = VideoProcessor(
roboflow_api_key=args.roboflow_api_key,
model_id=args.model_id,
source_video_path=args.source_video_path,
target_video_path=args.target_video_path,
confidence_threshold=args.confidence_threshold,
iou_threshold=args.iou_threshold,
)
processor.process_video()
+3 -2
View File
@@ -1,4 +1,5 @@
supervision>=0.15.0rc1
gdown
inference
supervision
tqdm
ultralytics
gdown
+44 -27
View File
@@ -1,7 +1,7 @@
site_name: Supervision
site_url: https://roboflow.github.io/supervision
site_url: https://supervision.roboflow.com/
site_author: Roboflow
site_description: A set of easy-to-use utils that will come in handy in any Computer Vision project
site_description: A set of easy-to-use utilities that will come in handy in any computer vision project.
repo_name: roboflow/supervision
repo_url: https://github.com/roboflow/supervision
edit_uri: https://github.com/roboflow/supervision/tree/main/docs
@@ -26,35 +26,42 @@ extra_css:
nav:
- Home: index.md
- Quickstart:
- Detections: quickstart/detections.md
- Classifications:
- Core: classification/core.md
- Detections:
- Core: detection/core.md
- Annotate: detection/annotate.md
- Utils: detection/utils.md
- Tools:
- Polygon Zone: detection/tools/polygon_zone.md
- Inference Slicer: detection/tools/inference_slicer.md
- Annotators: annotators.md
- Trackers: trackers.md
- Datasets: datasets.md
- Metrics:
- Object Detection: metrics/detection.md
- Draw:
- Utils: draw/utils.md
- Utils:
- Video: utils/video.md
- Image: utils/image.md
- Notebook: utils/notebook.md
- File: utils/file.md
- How to:
- Detect and Annotate: how_to/detect_and_annotate.md
- Track Objects: how_to/track_objects.md
- Filter Detections: how_to/filter_detections.md
- API:
- Classifications:
- Core: classification/core.md
- Detections:
- Core: detection/core.md
- Utils: detection/utils.md
- Tools:
- Line Zone: detection/tools/line_zone.md
- Polygon Zone: detection/tools/polygon_zone.md
- Inference Slicer: detection/tools/inference_slicer.md
- Detection Smoother: detection/tools/smoother.md
- Annotators: annotators.md
- Trackers: trackers.md
- Datasets: datasets.md
- Metrics:
- Object Detection: metrics/detection.md
- Draw:
- Color: draw/color.md
- Utils: draw/utils.md
- Utils:
- Video: utils/video.md
- Image: utils/image.md
- Notebook: utils/notebook.md
- File: utils/file.md
- Assets: assets.md
- Changelog: changelog.md
theme:
name: 'material'
logo: https://media.roboflow.com/open-source/supervision/supervision-lenny.png
favicon: https://media.roboflow.com/open-source/supervision/supervision-lenny.png
logo: assets/supervision-lenny.png
favicon: assets/supervision-lenny.png
custom_dir: docs/theme
palette:
# Palette for light mode
- scheme: default
@@ -72,6 +79,9 @@ theme:
font:
text: Roboto
code: Roboto Mono
features:
- content.code.copy
- content.code.annotate
plugins:
- mkdocstrings
@@ -87,3 +97,10 @@ markdown_extensions:
alternate_style: true
- toc:
permalink: true
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
extra_javascript:
- "https://widget.kapa.ai/kapa-widget.bundle.js"
- "javascript/init_kapa_widget.js"
Generated
+1838 -1386
View File
File diff suppressed because it is too large Load Diff
+45 -38
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "supervision"
version = "0.15.0"
version = "0.18.0"
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>"]
@@ -10,7 +10,7 @@ packages = [{include = "supervision"}]
homepage = "https://github.com/roboflow/supervision"
repository = "https://github.com/roboflow/supervision"
documentation = "https://github.com/roboflow/supervision/blob/main/README.md"
keywords = ["machine-learning", "deep-learning", "vision", "ML", "DL", "AI", "YOLOv5", "YOLOv8", "Roboflow"]
keywords = ["machine-learning", "deep-learning", "vision", "ML", "DL", "AI", "Roboflow"]
classifiers=[
'Development Status :: 4 - Beta',
@@ -19,10 +19,6 @@ classifiers=[
'Intended Audience :: Science/Research',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3 :: Only',
'Topic :: Software Development',
'Topic :: Scientific/Engineering',
@@ -35,51 +31,43 @@ classifiers=[
]
[tool.poetry.dependencies]
python = ">=3.8,<3.12.0"
numpy = "^1.20.0"
matplotlib = "^3.7.1"
pyyaml = "^6.0"
pillow = ">=9.4,<11.0"
opencv-python = { version = "^4.8.0.74", optional = true }
opencv-python-headless = "^4.8.0.74"
scipy = "^1.9.0"
python = "^3.8"
numpy = ">=1.21.2"
scipy = [
{ version = "1.10.0", python = "<3.9" },
{ version = "^1.10.0", python = ">=3.9" }
]
matplotlib = ">=3.6.0"
pyyaml = ">=5.3"
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"]
assets = ["requests","tqdm"]
[tool.poetry.group.dev.dependencies]
twine = "^4.0.2"
pytest = "^7.2.2"
wheel = "^0.40.0"
notebook = "^6.5.3"
build = "^0.10.0"
ruff = "^0.0.280"
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"
black = "^23.7.0"
mypy = "^1.4.1"
pre-commit = "^3.3.3"
flake8 = { version = "*", python = ">=3.8.1,<3.12.0" }
tox = "^4.11.4"
[tool.poetry.group.docs.dependencies]
mkdocs-material = "^9.1.4"
mkdocstrings = {extras = ["python"], version = "^0.20.0"}
mkdocs-material = {extras = ["imaging"], version = "^9.5.5"}
mkdocstrings = {extras = ["python"], version = ">=0.20,<0.25"}
[tool.flake8]
exclude = ".venv"
max-complexity = 10
max-line-length = 88
extend-ignore = """
W503,
E203,
E701,
C901,
"""
per-file-ignores = """
__init__.py: F401
"""
[tool.isort]
line_length = 88
@@ -87,7 +75,7 @@ profile = "black"
[tool.bandit]
target = ["test", "supervision"]
tests = ["B201", "B301"]
tests = ["B201", "B301", "B318", "B314", "B303", "B413", "B412", "B410"]
[tool.autoflake]
check = true
@@ -153,6 +141,7 @@ exclude = [
# Same as Black.
line-length = 88
indent-width = 4
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
@@ -167,16 +156,34 @@ convention = "google"
[tool.ruff.per-file-ignores]
"__init__.py" = ["E402","F401"]
"supervision/assets/list.py" = ["E501"]
[tool.ruff.lint.mccabe]
# Flag errors (`C901`) whenever the complexity level exceeds 5.
max-complexity = 20
[tool.ruff.pylint]
max-args = 20
[tool.ruff.format]
# Like Black, use double quotes for strings.
quote-style = "double"
# Like Black, indent with spaces, rather than tabs.
indent-style = "space"
# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false
# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"
[tool.setuptools]
include-package-data = false
[tool.setuptools.packages.find]
exclude = ["docs*", "test*"]
exclude = ["docs*", "test*","examples*"]
[build-system]
requires = ["poetry-core"]
+26 -1
View File
@@ -11,11 +11,22 @@ from supervision.annotators.core import (
BoundingBoxAnnotator,
BoxCornerAnnotator,
CircleAnnotator,
ColorAnnotator,
DotAnnotator,
EllipseAnnotator,
HaloAnnotator,
HeatMapAnnotator,
LabelAnnotator,
MaskAnnotator,
OrientedBoxAnnotator,
PercentageBarAnnotator,
PixelateAnnotator,
PolygonAnnotator,
RoundBoxAnnotator,
TraceAnnotator,
TriangleAnnotator,
)
from supervision.annotators.utils import ColorLookup
from supervision.classification.core import Classifications
from supervision.dataset.core import (
BaseDataset,
@@ -27,17 +38,30 @@ from supervision.detection.core import Detections
from supervision.detection.line_counter import LineZone, LineZoneAnnotator
from supervision.detection.tools.inference_slicer import InferenceSlicer
from supervision.detection.tools.polygon_zone import PolygonZone, PolygonZoneAnnotator
from supervision.detection.tools.smoother import DetectionsSmoother
from supervision.detection.utils import (
box_iou_batch,
calculate_masks_centroids,
filter_polygons_by_area,
mask_to_polygons,
mask_to_xyxy,
move_boxes,
non_max_suppression,
polygon_to_mask,
polygon_to_xyxy,
scale_boxes,
)
from supervision.draw.color import Color, ColorPalette
from supervision.draw.utils import draw_filled_rectangle, draw_polygon, draw_text
from supervision.draw.utils import (
calculate_dynamic_line_thickness,
calculate_dynamic_text_scale,
draw_filled_rectangle,
draw_image,
draw_line,
draw_polygon,
draw_rectangle,
draw_text,
)
from supervision.geometry.core import Point, Position, Rect
from supervision.geometry.utils import get_polygon_center
from supervision.metrics.detection import ConfusionMatrix, MeanAveragePrecision
@@ -46,6 +70,7 @@ from supervision.utils.file import list_files_with_extensions
from supervision.utils.image import ImageSink, crop_image
from supervision.utils.notebook import plot_image, plot_images_grid
from supervision.utils.video import (
FPSMonitor,
VideoInfo,
VideoSink,
get_video_frames_generator,
File diff suppressed because it is too large Load Diff
+40 -8
View File
@@ -8,18 +8,29 @@ from supervision.draw.color import Color, ColorPalette
from supervision.geometry.core import Position
class ColorMap(Enum):
class ColorLookup(Enum):
"""
Enum for annotator color mapping.
Enumeration class to define strategies for mapping colors to annotations.
This enum supports three different lookup strategies:
- `INDEX`: Colors are determined by the index of the detection within the scene.
- `CLASS`: Colors are determined by the class label of the detected object.
- `TRACK`: Colors are determined by the tracking identifier of the object.
"""
INDEX = "index"
CLASS = "class"
TRACK = "track"
@classmethod
def list(cls):
return list(map(lambda c: c.value, cls))
def resolve_color_idx(
detections: Detections, detection_idx: int, color_map: ColorMap = ColorMap.CLASS
detections: Detections,
detection_idx: int,
color_lookup: Union[ColorLookup, np.ndarray] = ColorLookup.CLASS,
) -> int:
if detection_idx >= len(detections):
raise ValueError(
@@ -27,16 +38,23 @@ def resolve_color_idx(
f"is out of bounds for detections of length {len(detections)}"
)
if color_map == ColorMap.INDEX:
if isinstance(color_lookup, np.ndarray):
if len(color_lookup) != len(detections):
raise ValueError(
f"Length of color lookup {len(color_lookup)}"
f"does not match length of detections {len(detections)}"
)
return color_lookup[detection_idx]
elif color_lookup == ColorLookup.INDEX:
return detection_idx
elif color_map == ColorMap.CLASS:
elif color_lookup == ColorLookup.CLASS:
if detections.class_id is None:
raise ValueError(
"Could not resolve color by class because"
"Detections do not have class_id"
)
return detections.class_id[detection_idx]
elif color_map == ColorMap.TRACK:
elif color_lookup == ColorLookup.TRACK:
if detections.tracker_id is None:
raise ValueError(
"Could not resolve color by track because"
@@ -45,12 +63,26 @@ def resolve_color_idx(
return detections.tracker_id[detection_idx]
def resolve_color(color: Union[Color, ColorPalette], idx: int) -> Color:
def get_color_by_index(color: Union[Color, ColorPalette], idx: int) -> Color:
if isinstance(color, ColorPalette):
return color.by_idx(idx)
return color
def resolve_color(
color: Union[Color, ColorPalette],
detections: Detections,
detection_idx: int,
color_lookup: Union[ColorLookup, np.ndarray] = ColorLookup.CLASS,
) -> Color:
idx = resolve_color_idx(
detections=detections,
detection_idx=detection_idx,
color_lookup=color_lookup,
)
return get_color_by_index(color=color, idx=idx)
class Trace:
def __init__(
self,
@@ -70,7 +102,7 @@ class Trace:
frame_id = np.full(len(detections), self.current_frame_id, dtype=int)
self.frame_id = np.concatenate([self.frame_id, frame_id])
self.xy = np.concatenate(
[self.xy, detections.get_anchor_coordinates(self.anchor)]
[self.xy, detections.get_anchors_coordinates(self.anchor)]
)
self.tracker_id = np.concatenate([self.tracker_id, detections.tracker_id])
+2
View File
@@ -0,0 +1,2 @@
from supervision.assets.downloader import download_assets
from supervision.assets.list import VideoAssets
+95
View File
@@ -0,0 +1,95 @@
import os
from hashlib import new as hash_new
from pathlib import Path
from shutil import copyfileobj
from typing import Union
from supervision.assets.list import VIDEO_ASSETS, VideoAssets
try:
from requests import get
from tqdm.auto import tqdm
except ImportError:
raise ValueError(
"\n"
"Please install requests and tqdm to download assets \n"
"or install supervision with assets \n"
"pip install supervision[assets] \n"
"\n"
)
def is_md5_hash_matching(filename: str, original_md5_hash: str) -> bool:
"""
Check if the MD5 hash of a file matches the original hash.
Parameters:
filename (str): The path to the file to be checked as a string.
original_md5_hash (str): The original MD5 hash to compare against.
Returns:
bool: True if the hashes match, False otherwise.
"""
if not os.path.exists(filename):
return False
with open(filename, "rb") as file:
file_contents = file.read()
computed_md5_hash = hash_new(name="MD5")
computed_md5_hash.update(file_contents)
return computed_md5_hash.hexdigest() == original_md5_hash
def download_assets(asset_name: Union[VideoAssets, str]) -> str:
"""
Download a specified asset if it doesn't already exist or is corrupted.
Parameters:
asset_name (Union[VideoAssets, str]): The name or type of the asset to be
downloaded.
Returns:
str: The filename of the downloaded asset.
Example:
```python
from supervision.assets import download_assets, VideoAssets
download_assets(VideoAssets.VEHICLES)
"vehicles.mp4"
```
"""
filename = asset_name.value if isinstance(asset_name, VideoAssets) else asset_name
if not Path(filename).exists() and filename in VIDEO_ASSETS:
print(f"Downloading {filename} assets \n")
response = get(VIDEO_ASSETS[filename][0], stream=True, allow_redirects=True)
response.raise_for_status()
file_size = int(response.headers.get("Content-Length", 0))
folder_path = Path(filename).expanduser().resolve()
folder_path.parent.mkdir(parents=True, exist_ok=True)
with tqdm.wrapattr(
response.raw, "read", total=file_size, desc="", colour="#a351fb"
) as raw_resp:
with folder_path.open("wb") as file:
copyfileobj(raw_resp, file)
elif Path(filename).exists():
if not is_md5_hash_matching(filename, VIDEO_ASSETS[filename][1]):
print("File corrupted. Re-downloading... \n")
os.remove(filename)
return download_assets(filename)
print(f"{filename} asset download complete. \n")
else:
valid_assets = ", ".join(asset.value for asset in VideoAssets)
raise ValueError(
f"Invalid asset. It should be one of the following: {valid_assets}."
)
return filename
+65
View File
@@ -0,0 +1,65 @@
from enum import Enum
from typing import Dict, Tuple
BASE_VIDEO_URL = "https://media.roboflow.com/supervision/video-examples/"
class VideoAssets(Enum):
"""
Each member of this enum represents a video asset. The value associated with each
member is the filename of the video.
| Enum Member | Video Filename | Video URL |
|------------------------|----------------------------|---------------------------------------------------------------------------------------|
| `VEHICLES` | `vehicles.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/vehicles.mp4) |
| `MILK_BOTTLING_PLANT` | `milk-bottling-plant.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/milk-bottling-plant.mp4) |
| `VEHICLES_2` | `vehicles-2.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/vehicles-2.mp4) |
| `GROCERY_STORE` | `grocery-store.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/grocery-store.mp4) |
| `SUBWAY` | `subway.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/subway.mp4) |
| `MARKET_SQUARE` | `market-square.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/market-square.mp4) |
| `PEOPLE_WALKING` | `people-walking.mp4` | [Link](https://media.roboflow.com/supervision/video-examples/people-walking.mp4) |
""" # noqa: E501 // docs
VEHICLES = "vehicles.mp4"
MILK_BOTTLING_PLANT = "milk-bottling-plant.mp4"
VEHICLES_2 = "vehicles-2.mp4"
GROCERY_STORE = "grocery-store.mp4"
SUBWAY = "subway.mp4"
MARKET_SQUARE = "market-square.mp4"
PEOPLE_WALKING = "people-walking.mp4"
@classmethod
def list(cls):
return list(map(lambda c: c.value, cls))
VIDEO_ASSETS: Dict[str, Tuple[str, str]] = {
VideoAssets.VEHICLES.value: (
f"{BASE_VIDEO_URL}{VideoAssets.VEHICLES.value}",
"8155ff4e4de08cfa25f39de96483f918",
),
VideoAssets.VEHICLES_2.value: (
f"{BASE_VIDEO_URL}{VideoAssets.VEHICLES_2.value}",
"830af6fba21ffbf14867a7fea595937b",
),
VideoAssets.MILK_BOTTLING_PLANT.value: (
f"{BASE_VIDEO_URL}{VideoAssets.MILK_BOTTLING_PLANT.value}",
"9e8fb6e883f842a38b3d34267290bdc7",
),
VideoAssets.GROCERY_STORE.value: (
f"{BASE_VIDEO_URL}{VideoAssets.GROCERY_STORE.value}",
"11402e7b861c1980527d3d74cbe3b366",
),
VideoAssets.SUBWAY.value: (
f"{BASE_VIDEO_URL}{VideoAssets.SUBWAY.value}",
"453475750691fb23c56a0cffef089194",
),
VideoAssets.MARKET_SQUARE.value: (
f"{BASE_VIDEO_URL}{VideoAssets.MARKET_SQUARE.value}",
"859179bf4a21f80a8baabfdb2ed716dc",
),
VideoAssets.PEOPLE_WALKING.value: (
f"{BASE_VIDEO_URL}{VideoAssets.PEOPLE_WALKING.value}",
"0574c053c8686c3f1dc0aa3743e45cb9",
),
}
+83 -35
View File
@@ -5,8 +5,6 @@ from typing import Any, Optional, Tuple
import numpy as np
from supervision.utils.internal import deprecated
def _validate_class_ids(class_id: Any, n: int) -> None:
"""
@@ -41,71 +39,121 @@ class Classifications:
_validate_class_ids(self.class_id, n)
_validate_confidence(self.confidence, n)
def __len__(self) -> int:
"""
Returns the number of classifications.
"""
return len(self.class_id)
@classmethod
@deprecated(
"""
This method is deprecated and removed in 0.16.0 release.
Use sv.Classifications.from_ultralytics() instead as it is more generic and
can be used for detections from any ultralytics.engine.results.Results Object
"""
)
def from_yolov8(cls, yolov8_results) -> Classifications:
def from_clip(cls, clip_results) -> Classifications:
"""
Creates a Classifications instance from a
[YOLOv8](https://github.com/ultralytics/ultralytics) inference result.
[clip](https://github.com/openai/clip) inference result.
Args:
yolov8_results (ultralytics.yolo.engine.results.Results):
The output Results instance from YOLOv8
clip_results (np.ndarray): The inference result from clip model.
Returns:
Classifications: A new Classifications object.
Example:
```python
>>> import cv2
>>> from ultralytics import YOLO
>>> import supervision as sv
from PIL import Image
import clip
import supervision as sv
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = YOLO('yolov8s-cls.pt')
>>> result = model(image)[0]
>>> classifications = sv.Classifications.from_yolov8(result)
model, preprocess = clip.load('ViT-B/32')
image = cv2.imread(SOURCE_IMAGE_PATH)
image = preprocess(image).unsqueeze(0)
text = clip.tokenize(["a diagram", "a dog", "a cat"])
output, _ = model(image, text)
classifications = sv.Classifications.from_clip(output)
```
"""
confidence = yolov8_results.probs.data.cpu().numpy()
return cls(class_id=np.arange(confidence.shape[0]), confidence=confidence)
confidence = clip_results.softmax(dim=-1).cpu().detach().numpy()[0]
if len(confidence) == 0:
return cls(class_id=np.array([]), confidence=np.array([]))
class_ids = np.arange(len(confidence))
return cls(class_id=class_ids, confidence=confidence)
@classmethod
def from_ultralytics(cls, ultralytics_results) -> Classifications:
"""
Creates a Classifications instance from a
(https://github.com/ultralytics/ultralytics) inference result.
[ultralytics](https://github.com/ultralytics/ultralytics) inference result.
Args:
ultralytics_results (ultralytics.engine.results.Results):
The output Results instance from ultralytics model
The inference result from ultralytics model.
Returns:
Classifications: A new Classifications object.
Example:
```python
>>> import cv2
>>> from ultralytics import YOLO
>>> import supervision as sv
import cv2
from ultralytics import YOLO
import supervision as sv
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = YOLO('yolov8n-cls.pt')
>>> model = YOLO('yolov8s-cls.pt')
image = cv2.imread(SOURCE_IMAGE_PATH)
model = YOLO('yolov8n-cls.pt')
>>> result = model(image)[0]
>>> classifications = sv.Classifications.from_ultralytics(result)
output = model(image)[0]
classifications = sv.Classifications.from_ultralytics(output)
```
"""
confidence = ultralytics_results.probs.data.cpu().numpy()
return cls(class_id=np.arange(confidence.shape[0]), confidence=confidence)
@classmethod
def from_timm(cls, timm_results) -> Classifications:
"""
Creates a Classifications instance from a
[timm](https://huggingface.co/docs/hub/timm) inference result.
Args:
timm_results: The inference result from timm model.
Returns:
Classifications: A new Classifications object.
Example:
```python
from PIL import Image
import timm
from timm.data import resolve_data_config, create_transform
import supervision as sv
model = timm.create_model(
model_name='hf-hub:nateraw/resnet50-oxford-iiit-pet',
pretrained=True
).eval()
config = resolve_data_config({}, model=model)
transform = create_transform(**config)
image = Image.open(SOURCE_IMAGE_PATH).convert('RGB')
x = transform(image).unsqueeze(0)
output = model(x)
classifications = sv.Classifications.from_timm(output)
```
"""
confidence = timm_results.cpu().detach().numpy()[0]
if len(confidence) == 0:
return cls(class_id=np.array([]), confidence=np.array([]))
class_id = np.arange(len(confidence))
return cls(class_id=class_id, confidence=confidence)
def get_top_k(self, k: int) -> Tuple[np.ndarray, np.ndarray]:
"""
Retrieve the top k class IDs and confidences,
@@ -120,11 +168,11 @@ class Classifications:
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> classifications = sv.Classifications(...)
classifications = sv.Classifications(...)
>>> classifications.get_top_k(1)
classifications.get_top_k(1)
(array([1]), array([0.9]))
```
+1
View File
@@ -0,0 +1 @@
CLASS_NAME_DATA_FIELD = "class_name"
+82 -87
View File
@@ -118,13 +118,13 @@ class DetectionDataset(BaseDataset):
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> ds = sv.DetectionDataset(...)
>>> train_ds, test_ds = ds.split(split_ratio=0.7,
... random_state=42, shuffle=True)
>>> len(train_ds), len(test_ds)
(700, 300)
ds = sv.DetectionDataset(...)
train_ds, test_ds = ds.split(split_ratio=0.7,
random_state=42, shuffle=True)
len(train_ds), len(test_ds)
# (700, 300)
```
"""
@@ -165,9 +165,8 @@ class DetectionDataset(BaseDataset):
where the images should be saved.
If not provided, images will not be saved.
annotations_directory_path (Optional[str]): The path to
the directory where the annotations in
PASCAL VOC format should be saved. If not provided,
annotations will not be saved.
the directory where the annotations in PASCAL VOC format should be
saved. If not provided, annotations will not be saved.
min_image_area_percentage (float): The minimum percentage of
detection area relative to
the image area for a detection to be included.
@@ -178,7 +177,7 @@ class DetectionDataset(BaseDataset):
Argument is used only for segmentation datasets.
approximation_percentage (float): The percentage of
polygon points to be removed from the input polygon,
in the range [0, 1). Argument is used only for segmentation datasets.
in the range [0, 1). Argument is used only for segmentation datasets.
"""
if images_directory_path:
save_dataset_images(
@@ -232,24 +231,24 @@ class DetectionDataset(BaseDataset):
Example:
```python
>>> import roboflow
>>> from roboflow import Roboflow
>>> import supervision as sv
import roboflow
from roboflow import Roboflow
import supervision as sv
>>> roboflow.login()
roboflow.login()
>>> rf = Roboflow()
rf = Roboflow()
>>> project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
>>> dataset = project.version(PROJECT_VERSION).download("voc")
project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
dataset = project.version(PROJECT_VERSION).download("voc")
>>> ds = sv.DetectionDataset.from_pascal_voc(
... images_directory_path=f"{dataset.location}/train/images",
... annotations_directory_path=f"{dataset.location}/train/labels"
... )
ds = sv.DetectionDataset.from_pascal_voc(
images_directory_path=f"{dataset.location}/train/images",
annotations_directory_path=f"{dataset.location}/train/labels"
)
>>> ds.classes
['dog', 'person']
ds.classes
# ['dog', 'person']
```
"""
@@ -289,25 +288,24 @@ class DetectionDataset(BaseDataset):
Example:
```python
>>> import roboflow
>>> from roboflow import Roboflow
>>> import supervision as sv
import roboflow
from roboflow import Roboflow
import supervision as sv
>>> roboflow.login()
roboflow.login()
rf = Roboflow()
>>> rf = Roboflow()
project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
dataset = project.version(PROJECT_VERSION).download("yolov5")
>>> project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
>>> dataset = project.version(PROJECT_VERSION).download("yolov5")
ds = sv.DetectionDataset.from_yolo(
images_directory_path=f"{dataset.location}/train/images",
annotations_directory_path=f"{dataset.location}/train/labels",
data_yaml_path=f"{dataset.location}/data.yaml"
)
>>> ds = sv.DetectionDataset.from_yolo(
... images_directory_path=f"{dataset.location}/train/images",
... annotations_directory_path=f"{dataset.location}/train/labels",
... data_yaml_path=f"{dataset.location}/data.yaml"
... )
>>> ds.classes
['dog', 'person']
ds.classes
# ['dog', 'person']
```
"""
classes, images, annotations = load_yolo_annotations(
@@ -395,24 +393,23 @@ class DetectionDataset(BaseDataset):
Example:
```python
>>> import roboflow
>>> from roboflow import Roboflow
>>> import supervision as sv
import roboflow
from roboflow import Roboflow
import supervision as sv
>>> roboflow.login()
roboflow.login()
rf = Roboflow()
>>> rf = Roboflow()
project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
dataset = project.version(PROJECT_VERSION).download("coco")
>>> project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
>>> dataset = project.version(PROJECT_VERSION).download("coco")
ds = sv.DetectionDataset.from_coco(
images_directory_path=f"{dataset.location}/train",
annotations_path=f"{dataset.location}/train/_annotations.coco.json",
)
>>> ds = sv.DetectionDataset.from_coco(
... images_directory_path=f"{dataset.location}/train",
... annotations_path=f"{dataset.location}/train/_annotations.coco.json",
... )
>>> ds.classes
['dog', 'person']
ds.classes
# ['dog', 'person']
```
"""
classes, images, annotations = load_coco_annotations(
@@ -487,25 +484,25 @@ class DetectionDataset(BaseDataset):
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> ds_1 = sv.DetectionDataset(...)
>>> len(ds_1)
100
>>> ds_1.classes
['dog', 'person']
ds_1 = sv.DetectionDataset(...)
len(ds_1)
# 100
ds_1.classes
# ['dog', 'person']
>>> ds_2 = sv.DetectionDataset(...)
>>> len(ds_2)
200
>>> ds_2.classes
['cat']
ds_2 = sv.DetectionDataset(...)
len(ds_2)
# 200
ds_2.classes
# ['cat']
>>> ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])
>>> len(ds_merged)
300
>>> ds_merged.classes
['cat', 'dog', 'person']
ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])
len(ds_merged)
# 300
ds_merged.classes
# ['cat', 'dog', 'person']
```
"""
merged_images, merged_annotations = {}, {}
@@ -563,8 +560,7 @@ class ClassificationDataset(BaseDataset):
split_ratio (float, optional): The ratio of the training
set to the entire dataset.
random_state (int, optional): The seed for the
random number generator.
This is used for reproducibility.
random number generator. This is used for reproducibility.
shuffle (bool, optional): Whether to shuffle the data before splitting.
Returns:
@@ -573,13 +569,13 @@ class ClassificationDataset(BaseDataset):
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> cd = sv.ClassificationDataset(...)
>>> train_cd,test_cd = cd.split(split_ratio=0.7,
... random_state=42,shuffle=True)
>>> len(train_cd), len(test_cd)
(700, 300)
cd = sv.ClassificationDataset(...)
train_cd,test_cd = cd.split(split_ratio=0.7,
random_state=42,shuffle=True)
len(train_cd), len(test_cd)
# (700, 300)
```
"""
image_names = list(self.images.keys())
@@ -641,20 +637,19 @@ class ClassificationDataset(BaseDataset):
Example:
```python
>>> import roboflow
>>> from roboflow import Roboflow
>>> import supervision as sv
import roboflow
from roboflow import Roboflow
import supervision as sv
>>> roboflow.login()
roboflow.login()
rf = Roboflow()
>>> rf = Roboflow()
project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
dataset = project.version(PROJECT_VERSION).download("folder")
>>> project = rf.workspace(WORKSPACE_ID).project(PROJECT_ID)
>>> dataset = project.version(PROJECT_VERSION).download("folder")
>>> cd = sv.ClassificationDataset.from_folder_structure(
... root_directory_path=f"{dataset.location}/train"
... )
cd = sv.ClassificationDataset.from_folder_structure(
root_directory_path=f"{dataset.location}/train"
)
```
"""
classes = os.listdir(root_directory_path)
+9 -9
View File
@@ -1,11 +1,11 @@
import os
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from xml.dom.minidom import parseString
from xml.etree.ElementTree import Element, SubElement, parse, tostring
from xml.etree.ElementTree import Element, SubElement
import cv2
import numpy as np
from defusedxml.ElementTree import fromstring, parse, tostring
from supervision.dataset.utils import approximate_mask_with_polygons
from supervision.detection.core import Detections
@@ -129,7 +129,7 @@ def detections_to_pascal_voc(
annotation.append(next_object)
# Generate XML string
xml_string = parseString(tostring(annotation)).toprettyxml(indent=" ")
xml_string = fromstring(tostring(annotation)).toprettyxml(indent=" ")
return xml_string
@@ -268,12 +268,12 @@ def detections_from_xml_obj(
[extended_classes.index(class_name) for class_name in class_names]
)
if with_masks:
annotation = Detections(
xyxy=xyxy, mask=np.array(masks).astype(bool), class_id=class_id
)
else:
annotation = Detections(xyxy=xyxy, class_id=class_id)
annotation = Detections(
xyxy=xyxy.astype(np.float32),
mask=np.array(masks).astype(bool) if with_masks else None,
class_id=class_id,
)
return annotation, extended_classes
+1 -1
View File
@@ -149,7 +149,7 @@ def load_yolo_annotations(
annotations[image_path] = Detections.empty()
continue
lines = read_txt_file(str(annotation_path))
lines = read_txt_file(file_path=annotation_path, skip_empty=True)
h, w, _ = image.shape
resolution_wh = (w, h)
+16 -17
View File
@@ -26,9 +26,9 @@ class BoxAnnotator:
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
text_color: Color = Color.black(),
text_color: Color = Color.BLACK,
text_scale: float = 0.5,
text_thickness: int = 1,
text_padding: int = 10,
@@ -63,23 +63,22 @@ class BoxAnnotator:
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> classes = ['person', ...]
>>> image = ...
>>> detections = sv.Detections(...)
classes = ['person', ...]
image = ...
detections = sv.Detections(...)
>>> box_annotator = sv.BoxAnnotator()
>>> labels = [
... f"{classes[class_id]} {confidence:0.2f}"
... for _, _, confidence, class_id, _
... in detections
... ]
>>> annotated_frame = box_annotator.annotate(
... scene=image.copy(),
... detections=detections,
... labels=labels
... )
box_annotator = sv.BoxAnnotator()
labels = [
f"{classes[class_id]} {confidence:0.2f}"
for _, _, confidence, class_id, _ in detections
]
annotated_frame = box_annotator.annotate(
scene=image.copy(),
detections=detections,
labels=labels
)
```
"""
font = cv2.FONT_HERSHEY_SIMPLEX
+447 -260
View File
@@ -1,69 +1,31 @@
from __future__ import annotations
from dataclasses import astuple, dataclass
from typing import Any, Iterator, List, Optional, Tuple, Union
from contextlib import suppress
from dataclasses import dataclass, field
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
import numpy as np
from supervision.detection.utils import (
calculate_masks_centroids,
extract_ultralytics_masks,
get_data_item,
is_data_equal,
merge_data,
non_max_suppression,
process_roboflow_result,
validate_detections_fields,
xywh_to_xyxy,
)
from supervision.geometry.core import Position
from supervision.utils.internal import deprecated
def _validate_xyxy(xyxy: Any, n: int) -> None:
is_valid = isinstance(xyxy, np.ndarray) and xyxy.shape == (n, 4)
if not is_valid:
raise ValueError("xyxy must be 2d np.ndarray with (n, 4) shape")
def _validate_mask(mask: Any, n: int) -> None:
is_valid = mask is None or (
isinstance(mask, np.ndarray) and len(mask.shape) == 3 and mask.shape[0] == n
)
if not is_valid:
raise ValueError("mask must be 3d np.ndarray with (n, H, W) shape")
def validate_inference_callback(callback) -> None:
tmp_img = np.zeros((256, 256, 3), dtype=np.uint8)
res = callback(tmp_img)
if not isinstance(res, Detections):
raise ValueError("Callback function must return sv.Detection type")
def _validate_class_id(class_id: Any, n: int) -> None:
is_valid = class_id is None or (
isinstance(class_id, np.ndarray) and class_id.shape == (n,)
)
if not is_valid:
raise ValueError("class_id must be None or 1d np.ndarray with (n,) shape")
def _validate_confidence(confidence: Any, n: int) -> None:
is_valid = confidence is None or (
isinstance(confidence, np.ndarray) and confidence.shape == (n,)
)
if not is_valid:
raise ValueError("confidence must be None or 1d np.ndarray with (n,) shape")
def _validate_tracker_id(tracker_id: Any, n: int) -> None:
is_valid = tracker_id is None or (
isinstance(tracker_id, np.ndarray) and tracker_id.shape == (n,)
)
if not is_valid:
raise ValueError("tracker_id must be None or 1d np.ndarray with (n,) shape")
@dataclass
class Detections:
"""
Data class containing information about the detections in a video frame.
A dataclass representing detection results.
Attributes:
xyxy (np.ndarray): An array of shape `(n, 4)` containing
the bounding boxes coordinates in format `[x1, y1, x2, y2]`
@@ -75,6 +37,17 @@ class Detections:
`(n,)` containing the class ids of the detections.
tracker_id (Optional[np.ndarray]): An array of shape
`(n,)` containing the tracker ids of the detections.
data (Dict[str, Union[np.ndarray, List]]): A dictionary containing additional
data where each key is a string representing the data type, and the value
is either a NumPy array or a list of corresponding data.
!!! warning
The `data` field in the `sv.Detections` class is currently in an experimental
phase. Please be aware that its API and functionality are subject to change in
future updates as we continue to refine and improve its capabilities.
We encourage users to experiment with this feature and provide feedback, but
also to be prepared for potential modifications in upcoming releases.
"""
xyxy: np.ndarray
@@ -82,14 +55,17 @@ class Detections:
confidence: Optional[np.ndarray] = None
class_id: Optional[np.ndarray] = None
tracker_id: Optional[np.ndarray] = None
data: Dict[str, Union[np.ndarray, List]] = field(default_factory=dict)
def __post_init__(self):
n = len(self.xyxy)
_validate_xyxy(xyxy=self.xyxy, n=n)
_validate_mask(mask=self.mask, n=n)
_validate_class_id(class_id=self.class_id, n=n)
_validate_confidence(confidence=self.confidence, n=n)
_validate_tracker_id(tracker_id=self.tracker_id, n=n)
validate_detections_fields(
xyxy=self.xyxy,
mask=self.mask,
confidence=self.confidence,
class_id=self.class_id,
tracker_id=self.tracker_id,
data=self.data,
)
def __len__(self):
"""
@@ -106,11 +82,12 @@ class Detections:
Optional[float],
Optional[int],
Optional[int],
Dict[str, Union[np.ndarray, List]],
]
]:
"""
Iterates over the Detections object and yield a tuple of
`(xyxy, mask, confidence, class_id, tracker_id)` for each detection.
`(xyxy, mask, confidence, class_id, tracker_id, data)` for each detection.
"""
for i in range(len(self.xyxy)):
yield (
@@ -119,36 +96,18 @@ class Detections:
self.confidence[i] if self.confidence is not None else None,
self.class_id[i] if self.class_id is not None else None,
self.tracker_id[i] if self.tracker_id is not None else None,
get_data_item(self.data, i),
)
def __eq__(self, other: Detections):
return all(
[
np.array_equal(self.xyxy, other.xyxy),
any(
[
self.mask is None and other.mask is None,
np.array_equal(self.mask, other.mask),
]
),
any(
[
self.class_id is None and other.class_id is None,
np.array_equal(self.class_id, other.class_id),
]
),
any(
[
self.confidence is None and other.confidence is None,
np.array_equal(self.confidence, other.confidence),
]
),
any(
[
self.tracker_id is None and other.tracker_id is None,
np.array_equal(self.tracker_id, other.tracker_id),
]
),
np.array_equal(self.mask, other.mask),
np.array_equal(self.class_id, other.class_id),
np.array_equal(self.confidence, other.confidence),
np.array_equal(self.tracker_id, other.tracker_id),
is_data_equal(self.data, other.data),
]
)
@@ -167,14 +126,14 @@ class Detections:
Example:
```python
>>> import cv2
>>> import torch
>>> import supervision as sv
import cv2
import torch
import supervision as sv
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = torch.hub.load('ultralytics/yolov5', 'yolov5s')
>>> result = model(image)
>>> detections = sv.Detections.from_yolov5(result)
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')
result = model(image)
detections = sv.Detections.from_yolov5(result)
```
"""
yolov5_detections_predictions = yolov5_results.pred[0].cpu().cpu().numpy()
@@ -185,52 +144,19 @@ class Detections:
class_id=yolov5_detections_predictions[:, 5].astype(int),
)
@classmethod
@deprecated(
"""
This method is deprecated and removed in 0.15.0 release.
Use sv.Detections.from_ultralytics() instead as it is more generic and
can be used for detections from any ultralytics.engine.results.Results Object
"""
)
def from_yolov8(cls, yolov8_results) -> Detections:
"""
Creates a Detections instance from a
[YOLOv8](https://github.com/ultralytics/ultralytics) inference result.
Args:
yolov8_results (ultralytics.yolo.engine.results.Results):
The output Results instance from YOLOv8
Returns:
Detections: A new Detections object.
Example:
```python
>>> import cv2
>>> from ultralytics import YOLO
>>> import supervision as sv
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = YOLO('yolov8s.pt')
>>> result = model(image)[0]
>>> detections = sv.Detections.from_yolov8(result)
```
"""
return cls(
xyxy=yolov8_results.boxes.xyxy.cpu().numpy(),
confidence=yolov8_results.boxes.conf.cpu().numpy(),
class_id=yolov8_results.boxes.cls.cpu().numpy().astype(int),
mask=extract_ultralytics_masks(yolov8_results),
)
@classmethod
def from_ultralytics(cls, ultralytics_results) -> Detections:
"""
Creates a Detections instance from a
[YOLOv8](https://github.com/ultralytics/ultralytics) inference result.
!!! Note
`from_ultralytics` is compatible with
[detection](https://docs.ultralytics.com/tasks/detect/),
[segmentation](https://docs.ultralytics.com/tasks/segment/), and
[OBB](https://docs.ultralytics.com/tasks/obb/) models.
Args:
ultralytics_results (ultralytics.yolo.engine.results.Results):
The output Results instance from YOLOv8
@@ -240,23 +166,28 @@ class Detections:
Example:
```python
>>> import cv2
>>> from ultralytics import YOLO, FastSAM, SAM, RTDETR
>>> import supervision as sv
import cv2
import supervision as sv
from ultralytics import YOLO
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = YOLO('yolov8s.pt')
>>> model = SAM('sam_b.pt')
>>> model = SAM('mobile_sam.pt')
>>> model = FastSAM('FastSAM-s.pt')
>>> model = RTDETR('rtdetr-l.pt')
>>> # model inferences
>>> result = model(image)[0]
>>> # if tracker is enabled
>>> result = model.track(image)[0]
>>> detections = sv.Detections.from_ultralytics(result)
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = YOLO('yolov8s.pt')
result = model(image)[0]
detections = sv.Detections.from_ultralytics(result)
```
"""
""" # noqa: E501 // docs
if ultralytics_results.obb is not None:
return cls(
xyxy=ultralytics_results.obb.xyxy.cpu().numpy(),
data={"xyxyxyxy": ultralytics_results.obb.xyxyxyxy.cpu().numpy()},
confidence=ultralytics_results.obb.conf.cpu().numpy(),
class_id=ultralytics_results.obb.cls.cpu().numpy().astype(int),
tracker_id=ultralytics_results.obb.id.int().cpu().numpy()
if ultralytics_results.obb.id is not None
else None,
)
return cls(
xyxy=ultralytics_results.boxes.xyxy.cpu().numpy(),
@@ -286,17 +217,18 @@ class Detections:
Example:
```python
>>> import cv2
>>> from super_gradients.training import models
>>> import supervision as sv
import cv2
from super_gradients.training import models
import supervision as sv
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = models.get('yolo_nas_l', pretrained_weights="coco")
>>> result = list(model.predict(image, conf=0.35))[0]
>>> detections = sv.Detections.from_yolo_nas(result)
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = models.get('yolo_nas_l', pretrained_weights="coco")
result = list(model.predict(image, conf=0.35))[0]
detections = sv.Detections.from_yolo_nas(result)
```
"""
if np.asarray(yolo_nas_results.bboxes_xyxy).shape[0] == 0:
if np.asarray(yolo_nas_results.prediction.bboxes_xyxy).shape[0] == 0:
return cls.empty()
return cls(
@@ -305,6 +237,47 @@ class Detections:
class_id=yolo_nas_results.prediction.labels.astype(int),
)
@classmethod
def from_tensorflow(
cls, tensorflow_results: dict, resolution_wh: tuple
) -> Detections:
"""
Creates a Detections instance from a
[Tensorflow Hub](https://www.tensorflow.org/hub/tutorials/tf2_object_detection)
inference result.
Args:
tensorflow_results (dict):
The output results from Tensorflow Hub.
Returns:
Detections: A new Detections object.
Example:
```python
import tensorflow as tf
import tensorflow_hub as hub
import numpy as np
import cv2
module_handle = "https://tfhub.dev/tensorflow/centernet/hourglass_512x512_kpts/1"
model = hub.load(module_handle)
img = np.array(cv2.imread(SOURCE_IMAGE_PATH))
result = model(img)
detections = sv.Detections.from_tensorflow(result)
```
""" # noqa: E501 // docs
boxes = tensorflow_results["detection_boxes"][0].numpy()
boxes[:, [0, 2]] *= resolution_wh[0]
boxes[:, [1, 3]] *= resolution_wh[1]
boxes = boxes[:, [1, 0, 3, 2]]
return cls(
xyxy=boxes,
confidence=tensorflow_results["detection_scores"][0].numpy(),
class_id=tensorflow_results["detection_classes"][0].numpy().astype(int),
)
@classmethod
def from_deepsparse(cls, deepsparse_results) -> Detections:
"""
@@ -321,18 +294,18 @@ class Detections:
Example:
```python
>>> from deepsparse import Pipeline
>>> import supervision as sv
import supervision as sv
from deepsparse import Pipeline
>>> yolo_pipeline = Pipeline.create(
... task="yolo",
... model_path = "zoo:cv/detection/yolov5-l/pytorch/" \
... "ultralytics/coco/pruned80_quant-none"
>>> pipeline_outputs = yolo_pipeline(SOURCE_IMAGE_PATH,
... iou_thres=0.6, conf_thres=0.001)
>>> detections = sv.Detections.from_deepsparse(result)
yolo_pipeline = Pipeline.create(
task="yolo",
model_path = "zoo:cv/detection/yolov5-l/pytorch/ultralytics/coco/pruned80_quant-none"
)
result = yolo_pipeline(<SOURCE IMAGE PATH>)
detections = sv.Detections.from_deepsparse(result)
```
"""
""" # noqa: E501 // docs
if np.asarray(deepsparse_results.boxes[0]).shape[0] == 0:
return cls.empty()
@@ -345,9 +318,9 @@ class Detections:
@classmethod
def from_mmdetection(cls, mmdet_results) -> Detections:
"""
Creates a Detections instance from
a [mmdetection](https://github.com/open-mmlab/mmdetection) inference result.
Also supported for [mmyolo](https://github.com/open-mmlab/mmyolo)
Creates a Detections instance from a
[mmdetection](https://github.com/open-mmlab/mmdetection) and
[mmyolo](https://github.com/open-mmlab/mmyolo) inference result.
Args:
mmdet_results (mmdet.structures.DetDataSample):
@@ -358,16 +331,17 @@ class Detections:
Example:
```python
>>> import cv2
>>> import supervision as sv
>>> from mmdet.apis import DetInferencer
import cv2
import supervision as sv
from mmdet.apis import init_detector, inference_detector
>>> inferencer = DetInferencer(model_name, checkpoint, device)
>>> mmdet_result = inferencer(SOURCE_IMAGE_PATH, out_dir='./output',
... return_datasample=True)["predictions"][0]
>>> detections = sv.Detections.from_mmdet(mmdet_result)
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = init_detector(<CONFIG_PATH>, <WEIGHTS_PATH>, device=<DEVICE>)
result = inference_detector(model, image)
detections = sv.Detections.from_mmdetection(result)
```
"""
""" # noqa: E501 // docs
return cls(
xyxy=mmdet_results.pred_instances.bboxes.cpu().numpy(),
@@ -407,18 +381,20 @@ class Detections:
Example:
```python
>>> import cv2
>>> from detectron2.engine import DefaultPredictor
>>> from detectron2.config import get_cfg
>>> import supervision as sv
import cv2
import supervision as sv
from detectron2.engine import DefaultPredictor
from detectron2.config import get_cfg
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> cfg = get_cfg()
>>> cfg.merge_from_file("path/to/config.yaml")
>>> cfg.MODEL.WEIGHTS = "path/to/model_weights.pth"
>>> predictor = DefaultPredictor(cfg)
>>> result = predictor(image)
>>> detections = sv.Detections.from_detectron2(result)
image = cv2.imread(<SOURCE_IMAGE_PATH>)
cfg = get_cfg()
cfg.merge_from_file(<CONFIG_PATH>)
cfg.MODEL.WEIGHTS = <WEIGHTS_PATH>
predictor = DefaultPredictor(cfg)
result = predictor(image)
detections = sv.Detections.from_detectron2(result)
```
"""
@@ -432,14 +408,22 @@ class Detections:
)
@classmethod
def from_roboflow(cls, roboflow_result: dict) -> Detections:
def from_inference(cls, roboflow_result: Union[dict, Any]) -> Detections:
"""
Create a Detections object from the [Roboflow](https://roboflow.com/)
API inference result.
API inference result or the [Inference](https://inference.roboflow.com/)
package results. This method extracts bounding boxes, class IDs,
confidences, and class names from the Roboflow API result and encapsulates
them into a Detections object.
!!! note
Class names can be accessed using the key 'class_name' in the returned
object's data attribute.
Args:
roboflow_result (dict): The result from the
Roboflow API containing predictions.
roboflow_result (dict, any): The result from the
Roboflow API or Inference package containing predictions.
Returns:
(Detections): A Detections object containing the bounding boxes, class IDs,
@@ -447,27 +431,20 @@ class Detections:
Example:
```python
>>> import supervision as sv
import cv2
import supervision as sv
from inference.models.utils import get_roboflow_model
>>> roboflow_result = {
... "predictions": [
... {
... "x": 0.5,
... "y": 0.5,
... "width": 0.2,
... "height": 0.3,
... "class_id": 0,
... "class": "person",
... "confidence": 0.9
... },
... # ... more predictions ...
... ]
... }
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = get_roboflow_model(model_id="yolov8s-640")
>>> detections = sv.Detections.from_roboflow(roboflow_result)
result = model.infer(image)[0]
detections = sv.Detections.from_inference(result)
```
"""
xyxy, confidence, class_id, masks = process_roboflow_result(
with suppress(AttributeError):
roboflow_result = roboflow_result.dict(exclude_none=True, by_alias=True)
xyxy, confidence, class_id, masks, trackers, data = process_roboflow_result(
roboflow_result=roboflow_result
)
@@ -479,8 +456,44 @@ class Detections:
confidence=confidence,
class_id=class_id,
mask=masks,
tracker_id=trackers,
data=data,
)
@classmethod
@deprecated(
"`Detections.from_roboflow` is deprecated and will be removed in "
"`supervision-0.21.0`. Use `Detections.from_inference` instead."
)
def from_roboflow(cls, roboflow_result: Union[dict, Any]) -> Detections:
"""
Create a Detections object from the [Roboflow](https://roboflow.com/)
API inference result or the [Inference](https://inference.roboflow.com/)
package results.
Args:
roboflow_result (dict): The result from the
Roboflow API containing predictions.
Returns:
(Detections): A Detections object containing the bounding boxes, class IDs,
and confidences of the predictions.
Example:
```python
import cv2
import supervision as sv
from inference.models.utils import get_roboflow_model
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = get_roboflow_model(model_id="yolov8s-640")
result = model.infer(image)[0]
detections = sv.Detections.from_roboflow(result)
```
"""
return cls.from_inference(roboflow_result)
@classmethod
def from_sam(cls, sam_result: List[dict]) -> Detections:
"""
@@ -496,17 +509,17 @@ class Detections:
Example:
```python
>>> import supervision as sv
>>> from segment_anything import (
... sam_model_registry,
... SamAutomaticMaskGenerator
... )
import supervision as sv
from segment_anything import (
sam_model_registry,
SamAutomaticMaskGenerator
)
>>> sam_model_reg = sam_model_registry[MODEL_TYPE]
>>> sam = sam_model_reg(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)
sam_model_reg = sam_model_registry[MODEL_TYPE]
sam = sam_model_reg(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)
```
"""
@@ -523,6 +536,93 @@ class Detections:
xyxy = xywh_to_xyxy(boxes_xywh=xywh)
return cls(xyxy=xyxy, mask=mask)
@classmethod
def from_azure_analyze_image(
cls, azure_result: dict, class_map: Optional[Dict[int, str]] = None
) -> Detections:
"""
Creates a Detections instance from [Azure Image Analysis 4.0](
https://learn.microsoft.com/en-us/azure/ai-services/computer-vision/
concept-object-detection-40).
Args:
azure_result (dict): The result from Azure Image Analysis. It should
contain detected objects and their bounding box coordinates.
class_map (Optional[Dict[int, str]]): A mapping ofclass IDs (int) to class
names (str). If None, a new mapping is created dynamically.
Returns:
Detections: A new Detections object.
Example:
```python
import requests
import supervision as sv
image = open(input, "rb").read()
endpoint = "https://.cognitiveservices.azure.com/"
subscription_key = ""
headers = {
"Content-Type": "application/octet-stream",
"Ocp-Apim-Subscription-Key": subscription_key
}
response = requests.post(endpoint,
headers=self.headers,
data=image
).json()
detections = sv.Detections.from_azure_analyze_image(response)
```
"""
if "error" in azure_result:
raise ValueError(
f'Azure API returned an error {azure_result["error"]["message"]}'
)
xyxy, confidences, class_ids = [], [], []
is_dynamic_mapping = class_map is None
if is_dynamic_mapping:
class_map = {}
class_map = {value: key for key, value in class_map.items()}
for detection in azure_result["objectsResult"]["values"]:
bbox = detection["boundingBox"]
tags = detection["tags"]
x0 = bbox["x"]
y0 = bbox["y"]
x1 = x0 + bbox["w"]
y1 = y0 + bbox["h"]
for tag in tags:
confidence = tag["confidence"]
class_name = tag["name"]
class_id = class_map.get(class_name, None)
if is_dynamic_mapping and class_id is None:
class_id = len(class_map)
class_map[class_name] = class_id
if class_id is not None:
xyxy.append([x0, y0, x1, y1])
confidences.append(confidence)
class_ids.append(class_id)
if len(xyxy) == 0:
return Detections.empty()
return cls(
xyxy=np.array(xyxy),
class_id=np.array(class_ids),
confidence=np.array(confidences),
)
@classmethod
def from_paddledet(cls, paddledet_result) -> Detections:
"""
@@ -538,21 +638,21 @@ class Detections:
Example:
```python
>>> import supervision as sv
>>> import paddle
>>> from ppdet.engine import Trainer
>>> from ppdet.core.workspace import load_config
import supervision as sv
import paddle
from ppdet.engine import Trainer
from ppdet.core.workspace import load_config
>>> weights = (...)
>>> config = (...)
weights = ()
config = ()
>>> cfg = load_config(config)
>>> trainer = Trainer(cfg, mode='test')
>>> trainer.load_weights(weights)
cfg = load_config(config)
trainer = Trainer(cfg, mode='test')
trainer.load_weights(weights)
>>> paddledet_result = trainer.predict([images])[0]
paddledet_result = trainer.predict([images])[0]
>>> detections = sv.Detections.from_paddledet(paddledet_result)
detections = sv.Detections.from_paddledet(paddledet_result)
```
"""
@@ -576,9 +676,9 @@ class Detections:
Example:
```python
>>> from supervision import Detections
from supervision import Detections
>>> empty_detections = Detections.empty()
empty_detections = Detections.empty()
```
"""
return cls(
@@ -607,30 +707,67 @@ class Detections:
Example:
```python
>>> from supervision import Detections
import numpy as np
import supervision as sv
>>> detections_1 = Detections(...)
>>> detections_2 = Detections(...)
detections_1 = sv.Detections(
xyxy=np.array([[15, 15, 100, 100], [200, 200, 300, 300]]),
class_id=np.array([1, 2]),
data={'feature_vector': np.array([0.1, 0.2)])}
)
>>> merged_detections = Detections.merge([detections_1, detections_2])
detections_2 = sv.Detections(
xyxy=np.array([[30, 30, 120, 120]]),
class_id=np.array([1]),
data={'feature_vector': [np.array([0.3])]}
)
merged_detections = Detections.merge([detections_1, detections_2])
merged_detections.xyxy
array([[ 15, 15, 100, 100],
[200, 200, 300, 300],
[ 30, 30, 120, 120]])
merged_detections.class_id
array([1, 2, 1])
merged_detections.data['feature_vector']
array([0.1, 0.2, 0.3])
```
"""
if len(detections_list) == 0:
return Detections.empty()
detections_tuples_list = [astuple(detection) for detection in detections_list]
xyxy, mask, confidence, class_id, tracker_id = [
list(field) for field in zip(*detections_tuples_list)
]
for detections in detections_list:
validate_detections_fields(
xyxy=detections.xyxy,
mask=detections.mask,
confidence=detections.confidence,
class_id=detections.class_id,
tracker_id=detections.tracker_id,
data=detections.data,
)
def __all_not_none(item_list: List[Any]):
return all(x is not None for x in item_list)
xyxy = np.vstack([d.xyxy for d in detections_list])
xyxy = np.vstack(xyxy)
mask = np.vstack(mask) if __all_not_none(mask) else None
confidence = np.hstack(confidence) if __all_not_none(confidence) else None
class_id = np.hstack(class_id) if __all_not_none(class_id) else None
tracker_id = np.hstack(tracker_id) if __all_not_none(tracker_id) else None
def stack_or_none(name: str):
if all(d.__getattribute__(name) is None for d in detections_list):
return None
if any(d.__getattribute__(name) is None for d in detections_list):
raise ValueError(f"All or none of the '{name}' fields must be None")
return (
np.vstack([d.__getattribute__(name) for d in detections_list])
if name == "mask"
else np.hstack([d.__getattribute__(name) for d in detections_list])
)
mask = stack_or_none("mask")
confidence = stack_or_none("confidence")
class_id = stack_or_none("class_id")
tracker_id = stack_or_none("tracker_id")
data = merge_data([d.data for d in detections_list])
return cls(
xyxy=xyxy,
@@ -638,9 +775,10 @@ class Detections:
confidence=confidence,
class_id=class_id,
tracker_id=tracker_id,
data=data,
)
def get_anchor_coordinates(self, anchor: Position) -> np.ndarray:
def get_anchors_coordinates(self, anchor: Position) -> np.ndarray:
"""
Calculates and returns the coordinates of a specific anchor point
within the bounding boxes defined by the `xyxy` attribute. The anchor
@@ -667,6 +805,12 @@ class Detections:
(self.xyxy[:, 1] + self.xyxy[:, 3]) / 2,
]
).transpose()
elif anchor == Position.CENTER_OF_MASS:
if self.mask is None:
raise ValueError(
"Cannot use `Position.CENTER_OF_MASS` without a detection mask."
)
return calculate_masks_centroids(masks=self.mask)
elif anchor == Position.CENTER_LEFT:
return np.array(
[
@@ -701,35 +845,41 @@ class Detections:
raise ValueError(f"{anchor} is not supported.")
def __getitem__(
self, index: Union[int, slice, List[int], np.ndarray]
) -> Detections:
self, index: Union[int, slice, List[int], np.ndarray, str]
) -> Union[Detections, List, np.ndarray, None]:
"""
Get a subset of the Detections object.
Get a subset of the Detections object or access an item from its data field.
When provided with an integer, slice, list of integers, or a numpy array, this
method returns a new Detections object that represents a subset of the original
detections. When provided with a string, it accesses the corresponding item in
the data dictionary.
Args:
index (Union[int, slice, List[int], np.ndarray]):
The index or indices of the subset of the Detections
index (Union[int, slice, List[int], np.ndarray, str]): The index, indices,
or key to access a subset of the Detections or an item from the data.
Returns:
(Detections): A subset of the Detections object.
Union[Detections, Any]: A subset of the Detections object or an item from
the data field.
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> detections = sv.Detections(...)
detections = sv.Detections()
>>> first_detection = detections[0]
first_detection = detections[0]
first_10_detections = detections[0:10]
some_detections = detections[[0, 2, 4]]
class_0_detections = detections[detections.class_id == 0]
high_confidence_detections = detections[detections.confidence > 0.5]
>>> first_10_detections = detections[0:10]
>>> some_detections = detections[[0, 2, 4]]
>>> class_0_detections = detections[detections.class_id == 0]
>>> high_confidence_detections = detections[detections.confidence > 0.5]
feature_vector = detections['feature_vector']
```
"""
if isinstance(index, str):
return self.data.get(index)
if isinstance(index, int):
index = [index]
return Detections(
@@ -738,8 +888,44 @@ class Detections:
confidence=self.confidence[index] if self.confidence is not None else None,
class_id=self.class_id[index] if self.class_id is not None else None,
tracker_id=self.tracker_id[index] if self.tracker_id is not None else None,
data=get_data_item(self.data, index),
)
def __setitem__(self, key: str, value: Union[np.ndarray, List]):
"""
Set a value in the data dictionary of the Detections object.
Args:
key (str): The key in the data dictionary to set.
value (Union[np.ndarray, List]): The value to set for the key.
Example:
```python
import cv2
import supervision as sv
from ultralytics import YOLO
image = cv2.imread(<SOURCE_IMAGE_PATH>)
model = YOLO('yolov8s.pt')
result = model(image)[0]
detections = sv.Detections.from_ultralytics(result)
detections['names'] = [
model.model.names[class_id]
for class_id
in detections.class_id
]
```
"""
if not isinstance(value, (np.ndarray, list)):
raise TypeError("Value must be a np.ndarray or a list")
if isinstance(value, list):
value = np.array(value)
self.data[key] = value
@property
def area(self) -> np.ndarray:
"""
@@ -749,7 +935,7 @@ class Detections:
Returns:
np.ndarray: An array of floats containing the area of each detection
in the format of `(area_1, area_2, ..., area_n)`,
in the format of `(area_1, area_2, , area_n)`,
where n is the number of detections.
"""
if self.mask is not None:
@@ -764,7 +950,7 @@ class Detections:
Returns:
np.ndarray: An array of floats containing the area of each bounding
box in the format of `(area_1, area_2, ..., area_n)`,
box in the format of `(area_1, area_2, , area_n)`,
where n is the number of detections.
"""
return (self.xyxy[:, 3] - self.xyxy[:, 1]) * (self.xyxy[:, 2] - self.xyxy[:, 0])
@@ -777,7 +963,8 @@ class Detections:
Args:
threshold (float, optional): The intersection-over-union threshold
to use for non-maximum suppression. Defaults to 0.5.
to use for non-maximum suppression. I'm the lower the value the more
restrictive the NMS becomes. Defaults to 0.5.
class_agnostic (bool, optional): Whether to perform class-agnostic
non-maximum suppression. If True, the class_id of each detection
will be ignored. Defaults to False.
+119 -28
View File
@@ -1,83 +1,174 @@
from typing import Dict, Optional
from typing import Dict, Iterable, Optional, Tuple
import cv2
import numpy as np
from supervision.detection.core import Detections
from supervision.draw.color import Color
from supervision.geometry.core import Point, Rect, Vector
from supervision.geometry.core import Point, Position, Rect, Vector
class LineZone:
"""
Count the number of objects that cross a line.
This class is responsible for counting the number of objects that cross a
predefined line.
!!! warning
LineZone uses the `tracker_id`. Read
[here](https://supervision.roboflow.com/trackers/) to learn how to plug
tracking into your inference pipeline.
Attributes:
in_count (int): The number of objects that have crossed the line from outside
to inside.
out_count (int): The number of objects that have crossed the line from inside
to outside.
"""
def __init__(self, start: Point, end: Point):
def __init__(
self,
start: Point,
end: Point,
triggering_anchors: Iterable[Position] = (
Position.TOP_LEFT,
Position.TOP_RIGHT,
Position.BOTTOM_LEFT,
Position.BOTTOM_RIGHT,
),
):
"""
Initialize a LineCounter object.
Attributes:
Args:
start (Point): The starting point of the line.
end (Point): The ending point of the line.
triggering_anchors (List[sv.Position]): A list of positions
specifying which anchors of the detections bounding box
to consider when deciding on whether the detection
has passed the line counter or not. By default, this
contains the four corners of the detection's bounding box
"""
self.vector = Vector(start=start, end=end)
self.limits = self.calculate_region_of_interest_limits(vector=self.vector)
self.tracker_state: Dict[str, bool] = {}
self.in_count: int = 0
self.out_count: int = 0
self.triggering_anchors = triggering_anchors
def trigger(self, detections: Detections):
@staticmethod
def calculate_region_of_interest_limits(vector: Vector) -> Tuple[Vector, Vector]:
magnitude = vector.magnitude
if magnitude == 0:
raise ValueError("The magnitude of the vector cannot be zero.")
delta_x = vector.end.x - vector.start.x
delta_y = vector.end.y - vector.start.y
unit_vector_x = delta_x / magnitude
unit_vector_y = delta_y / magnitude
perpendicular_vector_x = -unit_vector_y
perpendicular_vector_y = unit_vector_x
start_region_limit = Vector(
start=vector.start,
end=Point(
x=vector.start.x + perpendicular_vector_x,
y=vector.start.y + perpendicular_vector_y,
),
)
end_region_limit = Vector(
start=vector.end,
end=Point(
x=vector.end.x - perpendicular_vector_x,
y=vector.end.y - perpendicular_vector_y,
),
)
return start_region_limit, end_region_limit
@staticmethod
def is_point_in_limits(point: Point, limits: Tuple[Vector, Vector]) -> bool:
cross_product_1 = limits[0].cross_product(point)
cross_product_2 = limits[1].cross_product(point)
return (cross_product_1 > 0) == (cross_product_2 > 0)
def trigger(self, detections: Detections) -> Tuple[np.ndarray, np.ndarray]:
"""
Update the in_count and out_count for the detections that cross the line.
Update the `in_count` and `out_count` based on the objects that cross the line.
Attributes:
detections (Detections): The detections for which to update the counts.
Args:
detections (Detections): A list of detections for which to update the
counts.
Returns:
A tuple of two boolean NumPy arrays. 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.
"""
for xyxy, _, confidence, class_id, tracker_id in detections:
# handle detections with no tracker_id
crossed_in = np.full(len(detections), False)
crossed_out = np.full(len(detections), False)
if len(detections) == 0:
return crossed_in, crossed_out
all_anchors = np.array(
[
detections.get_anchors_coordinates(anchor)
for anchor in self.triggering_anchors
]
)
for i, tracker_id in enumerate(detections.tracker_id):
if tracker_id is None:
continue
# we check if all four anchors of bbox are on the same side of vector
x1, y1, x2, y2 = xyxy
anchors = [
Point(x=x1, y=y1),
Point(x=x1, y=y2),
Point(x=x2, y=y1),
Point(x=x2, y=y2),
]
triggers = [self.vector.is_in(point=anchor) for anchor in anchors]
box_anchors = [Point(x=x, y=y) for x, y in all_anchors[:, i, :]]
in_limits = all(
[
self.is_point_in_limits(point=anchor, limits=self.limits)
for anchor in box_anchors
]
)
if not in_limits:
continue
triggers = [
self.vector.cross_product(point=anchor) > 0 for anchor in box_anchors
]
# detection is partially in and partially out
if len(set(triggers)) == 2:
continue
tracker_state = triggers[0]
# handle new detection
if tracker_id not in self.tracker_state:
self.tracker_state[tracker_id] = tracker_state
continue
# handle detection on the same side of the line
if self.tracker_state.get(tracker_id) == tracker_state:
continue
self.tracker_state[tracker_id] = tracker_state
if tracker_state:
self.in_count += 1
crossed_in[i] = True
else:
self.out_count += 1
crossed_out[i] = True
return crossed_in, crossed_out
class LineZoneAnnotator:
def __init__(
self,
thickness: float = 2,
color: Color = Color.white(),
color: Color = Color.WHITE,
text_thickness: float = 2,
text_color: Color = Color.black(),
text_color: Color = Color.BLACK,
text_scale: float = 0.5,
text_offset: float = 1.5,
text_padding: int = 10,
+11 -12
View File
@@ -3,7 +3,7 @@ from typing import Callable, Optional, Tuple
import numpy as np
from supervision.detection.core import Detections, validate_inference_callback
from supervision.detection.core import Detections
from supervision.detection.utils import move_boxes
from supervision.utils.image import crop_image
@@ -60,7 +60,6 @@ class InferenceSlicer:
self.iou_threshold = iou_threshold
self.callback = callback
self.thread_workers = thread_workers
validate_inference_callback(callback=callback)
def __call__(self, image: np.ndarray) -> Detections:
"""
@@ -78,20 +77,20 @@ class InferenceSlicer:
Example:
```python
>>> import cv2
>>> import supervision as sv
>>> from ultralytics import YOLO
import cv2
import supervision as sv
from ultralytics import YOLO
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = YOLO(...)
image = cv2.imread(SOURCE_IMAGE_PATH)
model = YOLO(...)
>>> def callback(image_slice: np.ndarray) -> sv.Detections:
... result = model(image_slice)[0]
... return sv.Detections.from_ultralytics(result)
def callback(image_slice: np.ndarray) -> sv.Detections:
result = model(image_slice)[0]
return sv.Detections.from_ultralytics(result)
>>> slicer = sv.InferenceSlicer(callback = callback)
slicer = sv.InferenceSlicer(callback = callback)
>>> detections = slicer(image)
detections = slicer(image)
```
"""
detections_list = []
+3 -3
View File
@@ -56,11 +56,11 @@ class PolygonZone:
"""
clipped_xyxy = clip_boxes(
boxes_xyxy=detections.xyxy, frame_resolution_wh=self.frame_resolution_wh
xyxy=detections.xyxy, resolution_wh=self.frame_resolution_wh
)
clipped_detections = replace(detections, xyxy=clipped_xyxy)
clipped_anchors = np.ceil(
clipped_detections.get_anchor_coordinates(anchor=self.triggering_position)
clipped_detections.get_anchors_coordinates(anchor=self.triggering_position)
).astype(int)
is_in_zone = self.mask[clipped_anchors[:, 1], clipped_anchors[:, 0]]
self.current_count = int(np.sum(is_in_zone))
@@ -90,7 +90,7 @@ class PolygonZoneAnnotator:
zone: PolygonZone,
color: Color,
thickness: int = 2,
text_color: Color = Color.black(),
text_color: Color = Color.BLACK,
text_scale: float = 0.5,
text_thickness: int = 1,
text_padding: int = 10,
+118
View File
@@ -0,0 +1,118 @@
from collections import defaultdict, deque
from copy import deepcopy
from typing import Optional
import numpy as np
from supervision.detection.core import Detections
class DetectionsSmoother:
"""
A utility class for smoothing detections over multiple frames in video tracking.
It maintains a history of detections for each track and provides smoothed
predictions based on these histories.
<video controls>
<source
src="https://media.roboflow.com/supervision-detection-smoothing.mp4"
type="video/mp4">
</video>
!!! warning
- `DetectionsSmoother` requires the `tracker_id` for each detection. Refer to
[Roboflow Trackers](https://supervision.roboflow.com/trackers/) for
information on integrating tracking into your inference pipeline.
- This class is not compatible with segmentation models.
Example:
```python
import supervision as sv
from ultralytics import YOLO
video_info = sv.VideoInfo.from_video_path(video_path=<SOURCE_FILE_PATH>)
frame_generator = sv.get_video_frames_generator(source_path=<SOURCE_FILE_PATH>)
model = YOLO(<MODEL_PATH>)
tracker = sv.ByteTrack(frame_rate=video_info.fps)
smoother = sv.DetectionsSmoother()
annotator = sv.BoundingBoxAnnotator()
with sv.VideoSink(<TARGET_FILE_PATH>, video_info=video_info) as sink:
for frame in frame_generator:
result = model(frame)[0]
detections = sv.Detections.from_ultralytics(result)
detections = tracker.update_with_detections(detections)
detections = smoother.update_with_detections(detections)
annotated_frame = bounding_box_annotator.annotate(frame.copy(), detections)
sink.write_frame(annotated_frame)
```
""" # noqa: E501 // docs
def __init__(self, length: int = 5) -> None:
"""
Args:
length (int): The maximum number of frames to consider for smoothing
detections. Defaults to 5.
"""
self.tracks = defaultdict(lambda: deque(maxlen=length))
def update_with_detections(self, detections: Detections) -> Detections:
"""
Updates the smoother with a new set of detections from a frame.
Args:
detections (Detections): The detections to add to the smoother.
"""
if detections.tracker_id is None:
print(
"Smoothing skipped. DetectionsSmoother requires tracker_id. Refer to "
"https://supervision.roboflow.com/trackers for more information."
)
return detections
for detection_idx in range(len(detections)):
tracker_id = detections.tracker_id[detection_idx]
if tracker_id is None:
continue
self.tracks[tracker_id].append(detections[detection_idx])
for track_id in self.tracks.keys():
if track_id not in detections.tracker_id:
self.tracks[track_id].append(None)
for track_id in list(self.tracks.keys()):
if all([d is None for d in self.tracks[track_id]]):
del self.tracks[track_id]
return self.get_smoothed_detections()
def get_track(self, track_id: int) -> Optional[Detections]:
track = self.tracks.get(track_id, None)
if track is None:
return None
track = [d for d in track if d is not None]
if len(track) == 0:
return None
ret = deepcopy(track[0])
ret.xyxy = np.mean([d.xyxy for d in track], axis=0)
ret.confidence = np.mean([d.confidence for d in track], axis=0)
return ret
def get_smoothed_detections(self) -> Detections:
tracked_detections = []
for track_id in self.tracks:
track = self.get_track(track_id)
if track is not None:
tracked_detections.append(track)
return Detections.merge(tracked_detections)
+319 -14
View File
@@ -1,8 +1,11 @@
from typing import List, Optional, Tuple
from itertools import chain
from typing import Any, Dict, List, Optional, Tuple, Union
import cv2
import numpy as np
from supervision.config import CLASS_NAME_DATA_FIELD
MIN_POLYGON_POINT_COUNT = 3
@@ -110,17 +113,15 @@ def non_max_suppression(
return keep[sort_index.argsort()]
def clip_boxes(
boxes_xyxy: np.ndarray, frame_resolution_wh: Tuple[int, int]
) -> np.ndarray:
def clip_boxes(xyxy: np.ndarray, resolution_wh: Tuple[int, int]) -> np.ndarray:
"""
Clips bounding boxes coordinates to fit within the frame resolution.
Args:
boxes_xyxy (np.ndarray): A numpy array of shape `(N, 4)` where each
xyxy (np.ndarray): A numpy array of shape `(N, 4)` where each
row corresponds to a bounding box in
the format `(x_min, y_min, x_max, y_max)`.
frame_resolution_wh (Tuple[int, int]): A tuple of the form `(width, height)`
resolution_wh (Tuple[int, int]): A tuple of the form `(width, height)`
representing the resolution of the frame.
Returns:
@@ -128,8 +129,8 @@ def clip_boxes(
corresponds to a bounding box with coordinates clipped to fit
within the frame resolution.
"""
result = np.copy(boxes_xyxy)
width, height = frame_resolution_wh
result = np.copy(xyxy)
width, height = resolution_wh
result[:, [0, 2]] = result[:, [0, 2]].clip(0, width)
result[:, [1, 3]] = result[:, [1, 3]].clip(0, height)
return result
@@ -301,7 +302,6 @@ def extract_ultralytics_masks(yolov8_results) -> Optional[np.ndarray]:
orig_shape = yolov8_results.orig_shape
inference_shape = tuple(yolov8_results.masks.data.shape[1:])
gain = 0
pad = (0, 0)
if inference_shape != orig_shape:
@@ -333,14 +333,30 @@ def extract_ultralytics_masks(yolov8_results) -> Optional[np.ndarray]:
def process_roboflow_result(
roboflow_result: dict,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray]]:
) -> Tuple[
np.ndarray,
np.ndarray,
np.ndarray,
Optional[np.ndarray],
Optional[np.ndarray],
Dict[str, List[np.ndarray]],
]:
if not roboflow_result["predictions"]:
return np.empty((0, 4)), np.empty(0), np.empty(0), None
return (
np.empty((0, 4)),
np.empty(0),
np.empty(0),
None,
None,
{CLASS_NAME_DATA_FIELD: np.empty(0)},
)
xyxy = []
confidence = []
class_id = []
class_name = []
masks = []
tracker_ids = []
image_width = int(roboflow_result["image"]["width"])
image_height = int(roboflow_result["image"]["height"])
@@ -358,7 +374,10 @@ def process_roboflow_result(
if "points" not in prediction:
xyxy.append([x_min, y_min, x_max, y_max])
class_id.append(prediction["class_id"])
class_name.append(prediction["class"])
confidence.append(prediction["confidence"])
if "tracker_id" in prediction:
tracker_ids.append(prediction["tracker_id"])
elif len(prediction["points"]) >= 3:
polygon = np.array(
[[point["x"], point["y"]] for point in prediction["points"]], dtype=int
@@ -366,26 +385,312 @@ def process_roboflow_result(
mask = polygon_to_mask(polygon, resolution_wh=(image_width, image_height))
xyxy.append([x_min, y_min, x_max, y_max])
class_id.append(prediction["class_id"])
class_name.append(prediction["class"])
confidence.append(prediction["confidence"])
masks.append(mask)
if "tracker_id" in prediction:
tracker_ids.append(prediction["tracker_id"])
xyxy = np.array(xyxy) if len(xyxy) > 0 else np.empty((0, 4))
confidence = np.array(confidence) if len(confidence) > 0 else np.empty(0)
class_id = np.array(class_id).astype(int) if len(class_id) > 0 else np.empty(0)
class_name = np.array(class_name) if len(class_name) > 0 else np.empty(0)
masks = np.array(masks, dtype=bool) if len(masks) > 0 else None
tracker_id = np.array(tracker_ids).astype(int) if len(tracker_ids) > 0 else None
data = {CLASS_NAME_DATA_FIELD: class_name}
return xyxy, confidence, class_id, masks
return xyxy, confidence, class_id, masks, tracker_id, data
def move_boxes(xyxy: np.ndarray, offset: np.ndarray) -> np.ndarray:
"""
Args:
Parameters:
xyxy (np.ndarray): An array of shape `(n, 4)` containing the bounding boxes
coordinates in format `[x1, y1, x2, y2]`
offset (np.array): An array of shape `(2,)` containing offset values in format
is `[dx, dy]`.
Returns:
(np.ndarray) repositioned bounding boxes
np.ndarray: Repositioned bounding boxes.
Example:
```python
import numpy as np
import supervision as sv
boxes = np.array([[10, 10, 20, 20], [30, 30, 40, 40]])
offset = np.array([5, 5])
moved_box = sv.move_boxes(boxes, offset)
print(moved_box)
# np.array([
# [15, 15, 25, 25],
# [35, 35, 45, 45]
# ])
```
"""
return xyxy + np.hstack([offset, offset])
def scale_boxes(xyxy: np.ndarray, factor: float) -> np.ndarray:
"""
Scale the dimensions of bounding boxes.
Parameters:
xyxy (np.ndarray): An array of shape `(n, 4)` containing the bounding boxes
coordinates in format `[x1, y1, x2, y2]`
factor (float): A float value representing the factor by which the box
dimensions are scaled. A factor greater than 1 enlarges the boxes, while a
factor less than 1 shrinks them.
Returns:
np.ndarray: Scaled bounding boxes.
Example:
```python
import numpy as np
import supervision as sv
boxes = np.array([[10, 10, 20, 20], [30, 30, 40, 40]])
factor = 1.5
scaled_bb = sv.scale_boxes(boxes, factor)
print(scaled_bb)
# np.array([
# [ 7.5, 7.5, 22.5, 22.5],
# [27.5, 27.5, 42.5, 42.5]
# ])
```
"""
centers = (xyxy[:, :2] + xyxy[:, 2:]) / 2
new_sizes = (xyxy[:, 2:] - xyxy[:, :2]) * factor
return np.concatenate((centers - new_sizes / 2, centers + new_sizes / 2), axis=1)
def calculate_masks_centroids(masks: np.ndarray) -> np.ndarray:
"""
Calculate the centroids of binary masks in a tensor.
Parameters:
masks (np.ndarray): A 3D NumPy array of shape (num_masks, height, width).
Each 2D array in the tensor represents a binary mask.
Returns:
A 2D NumPy array of shape (num_masks, 2), where each row contains the x and y
coordinates (in that order) of the centroid of the corresponding mask.
"""
num_masks, height, width = masks.shape
total_pixels = masks.sum(axis=(1, 2))
# offset for 1-based indexing
vertical_indices, horizontal_indices = np.indices((height, width)) + 0.5
# avoid division by zero for empty masks
total_pixels[total_pixels == 0] = 1
def sum_over_mask(indices: np.ndarray, axis: tuple) -> np.ndarray:
return np.tensordot(masks, indices, axes=axis)
aggregation_axis = ([1, 2], [0, 1])
centroid_x = sum_over_mask(horizontal_indices, aggregation_axis) / total_pixels
centroid_y = sum_over_mask(vertical_indices, aggregation_axis) / total_pixels
return np.column_stack((centroid_x, centroid_y)).astype(int)
def validate_xyxy(xyxy: Any) -> None:
expected_shape = "(_, 4)"
actual_shape = str(getattr(xyxy, "shape", None))
is_valid = isinstance(xyxy, np.ndarray) and xyxy.ndim == 2 and xyxy.shape[1] == 4
if not is_valid:
raise ValueError(
f"xyxy must be a 2D np.ndarray with shape {expected_shape}, but got shape "
f"{actual_shape}"
)
def validate_mask(mask: Any, n: int) -> None:
expected_shape = f"({n}, H, W)"
actual_shape = str(getattr(mask, "shape", None))
is_valid = mask is None or (
isinstance(mask, np.ndarray) and len(mask.shape) == 3 and mask.shape[0] == n
)
if not is_valid:
raise ValueError(
f"mask must be a 3D np.ndarray with shape {expected_shape}, but got shape "
f"{actual_shape}"
)
def validate_class_id(class_id: Any, n: int) -> None:
expected_shape = f"({n},)"
actual_shape = str(getattr(class_id, "shape", None))
is_valid = class_id is None or (
isinstance(class_id, np.ndarray) and class_id.shape == (n,)
)
if not is_valid:
raise ValueError(
f"class_id must be a 1D np.ndarray with shape {expected_shape}, but got "
f"shape {actual_shape}"
)
def validate_confidence(confidence: Any, n: int) -> None:
expected_shape = f"({n},)"
actual_shape = str(getattr(confidence, "shape", None))
is_valid = confidence is None or (
isinstance(confidence, np.ndarray) and confidence.shape == (n,)
)
if not is_valid:
raise ValueError(
f"confidence must be a 1D np.ndarray with shape {expected_shape}, but got "
f"shape {actual_shape}"
)
def validate_tracker_id(tracker_id: Any, n: int) -> None:
expected_shape = f"({n},)"
actual_shape = str(getattr(tracker_id, "shape", None))
is_valid = tracker_id is None or (
isinstance(tracker_id, np.ndarray) and tracker_id.shape == (n,)
)
if not is_valid:
raise ValueError(
f"tracker_id must be a 1D np.ndarray with shape {expected_shape}, but got "
f"shape {actual_shape}"
)
def validate_data(data: Dict[str, Any], n: int) -> None:
for key, value in data.items():
if isinstance(value, list):
if len(value) != n:
raise ValueError(f"Length of list for key '{key}' must be {n}")
elif isinstance(value, np.ndarray):
if value.ndim == 1 and value.shape[0] != n:
raise ValueError(f"Shape of np.ndarray for key '{key}' must be ({n},)")
elif value.ndim > 1 and value.shape[0] != n:
raise ValueError(
f"First dimension of np.ndarray for key '{key}' must have size {n}"
)
else:
raise ValueError(f"Value for key '{key}' must be a list or np.ndarray")
def validate_detections_fields(
xyxy: Any,
mask: Any,
class_id: Any,
confidence: Any,
tracker_id: Any,
data: Dict[str, Any],
) -> None:
validate_xyxy(xyxy)
n = len(xyxy)
validate_mask(mask, n)
validate_class_id(class_id, n)
validate_confidence(confidence, n)
validate_tracker_id(tracker_id, n)
validate_data(data, n)
def is_data_equal(data_a: Dict[str, np.ndarray], data_b: Dict[str, np.ndarray]) -> bool:
"""
Compares the data payloads of two Detections instances.
Args:
data_a, data_b: The data payloads of the instances.
Returns:
True if the data payloads are equal, False otherwise.
"""
return set(data_a.keys()) == set(data_b.keys()) and all(
np.array_equal(data_a[key], data_b[key]) for key in data_a
)
def merge_data(
data_list: List[Dict[str, Union[np.ndarray, List]]],
) -> Dict[str, Union[np.ndarray, List]]:
"""
Merges the data payloads of a list of Detections instances.
Args:
data_list: The data payloads of the instances.
Returns:
A single data payload containing the merged data, preserving the original data
types (list or np.ndarray).
Raises:
ValueError: If data values within a single object have different lengths or if
dictionaries have different keys.
"""
if not data_list:
return {}
all_keys_sets = [set(data.keys()) for data in data_list]
if not all(keys_set == all_keys_sets[0] for keys_set in all_keys_sets):
raise ValueError("All data dictionaries must have the same keys to merge.")
for data in data_list:
lengths = [len(value) for value in data.values()]
if len(set(lengths)) > 1:
raise ValueError(
"All data values within a single object must have equal length."
)
merged_data = {key: [] for key in all_keys_sets[0]}
for data in data_list:
for key in merged_data:
merged_data[key].append(data[key])
for key in merged_data:
if all(isinstance(item, list) for item in merged_data[key]):
merged_data[key] = list(chain.from_iterable(merged_data[key]))
elif all(isinstance(item, np.ndarray) for item in merged_data[key]):
ndim = merged_data[key][0].ndim
if ndim == 1:
merged_data[key] = np.hstack(merged_data[key])
elif ndim > 1:
merged_data[key] = np.vstack(merged_data[key])
else:
raise ValueError(f"Unexpected array dimension for key '{key}'.")
else:
raise ValueError(
f"Inconsistent data types for key '{key}'. Only np.ndarray and list "
f"types are allowed."
)
return merged_data
def get_data_item(
data: Dict[str, Union[np.ndarray, List]],
index: Union[int, slice, List[int], np.ndarray],
) -> Dict[str, Union[np.ndarray, List]]:
"""
Retrieve a subset of the data dictionary based on the given index.
Args:
data: The data dictionary of the Detections object.
index: The index or indices specifying the subset to retrieve.
Returns:
A subset of the data dictionary corresponding to the specified index.
"""
subset_data = {}
for key, value in data.items():
if isinstance(value, np.ndarray):
subset_data[key] = value[index]
elif isinstance(value, list):
if isinstance(index, slice):
subset_data[key] = value[index]
elif isinstance(index, (list, np.ndarray)):
subset_data[key] = [value[i] for i in index]
elif isinstance(index, int):
subset_data[key] = [value[index]]
else:
raise TypeError(f"Unsupported index type: {type(index)}")
else:
raise TypeError(f"Unsupported data type for key '{key}': {type(value)}")
return subset_data
+298 -38
View File
@@ -3,25 +3,56 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import List, Tuple
import matplotlib.pyplot as plt
from supervision.utils.internal import classproperty, deprecated
DEFAULT_COLOR_PALETTE = [
"#e6194b",
"#3cb44b",
"#ffe119",
"#0082c8",
"#f58231",
"#911eb4",
"#46f0f0",
"#f032e6",
"#d2f53c",
"#fabebe",
"#008080",
"#e6beff",
"#aa6e28",
"#fffac8",
"#800000",
"#aaffc3",
"A351FB",
"FF4040",
"FFA1A0",
"FF7633",
"FFB633",
"D1D435",
"4CFB12",
"94CF1A",
"40DE8A",
"1B9640",
"00D6C1",
"2E9CAA",
"00C4FF",
"364797",
"6675FF",
"0019EF",
"863AFF",
"530087",
"CD3AFF",
"FF97CA",
"FF39C9",
]
LEGACY_COLOR_PALETTE = [
"#A351FB",
"#E6194B",
"#3CB44B",
"#FFE119",
"#0082C8",
"#F58231",
"#911EB4",
"#46F0F0",
"#F032E6",
"#D2F53C",
"#FABEBE",
"#008080",
"#E6BEFF",
"#AA6E28",
"#FFFAC8",
"#800000",
"#AAFFC3",
]
ROBOFLOW_COLOR_PALETTE = ["C28DFC", "A351FB", "8315F9", "6706CE", "5905B3", "4D049A"]
def _validate_color_hex(color_hex: str):
color_hex = color_hex.lstrip("#")
@@ -33,21 +64,58 @@ def _validate_color_hex(color_hex: str):
@dataclass
class Color:
"""
Represents a color in RGB format.
This class provides methods to work with colors, including creating colors from hex
codes, converting colors to hex strings, RGB tuples, and BGR tuples.
Attributes:
r (int): Red channel value (0-255).
g (int): Green channel value (0-255).
b (int): Blue channel value (0-255).
Example:
```python
import supervision as sv
sv.Color.WHITE
# Color(r=255, g=255, b=255)
```
| Constant | Hex Code | RGB |
|------------|------------|------------------|
| `WHITE` | `#FFFFFF` | `(255, 255, 255)`|
| `BLACK` | `#000000` | `(0, 0, 0)` |
| `RED` | `#FF0000` | `(255, 0, 0)` |
| `GREEN` | `#00FF00` | `(0, 255, 0)` |
| `BLUE` | `#0000FF` | `(0, 0, 255)` |
| `YELLOW` | `#FFFF00` | `(255, 255, 0)` |
| `ROBOFLOW` | `#A351FB` | `(163, 81, 251)` |
"""
r: int
g: int
b: int
@classmethod
def from_hex(cls, color_hex: str):
def from_hex(cls, color_hex: str) -> Color:
"""
Creates a Color instance from a color hex string
Create a Color instance from a hex string.
:param color_hex: str : The color hex string in the format
of "fff", "ffffff", "#fff", or "#ffffff"
:return: Color : A Color instance representing the color
Args:
color_hex (str): Hex string of the color.
Returns:
Color: Instance representing the color.
Example:
color = Color.from_hex('#ff00ff')
```python
import supervision as sv
sv.Color.from_hex('#ff00ff')
# Color(r=255, g=0, b=255)
```
"""
_validate_color_hex(color_hex)
color_hex = color_hex.lstrip("#")
@@ -56,39 +124,122 @@ class Color:
r, g, b = (int(color_hex[i : i + 2], 16) for i in range(0, 6, 2))
return cls(r, g, b)
def as_hex(self) -> str:
"""
Converts the Color instance to a hex string.
Returns:
str: The hexadecimal color string.
Example:
```python
import supervision as sv
sv.Color(r=255, g=255, b=0).as_hex()
# '#ffff00'
```
"""
return f"#{self.r:02x}{self.g:02x}{self.b:02x}"
def as_rgb(self) -> Tuple[int, int, int]:
"""
Returns the color as a tuple of integers in the RGB format
Returns the color as an RGB tuple.
:return: Tuple[int, int, int] : The color in the RGB format
Returns:
Tuple[int, int, int]: RGB tuple.
Example:
```python
import supervision as sv
sv.Color(r=255, g=255, b=0).as_rgb()
# (255, 255, 0)
```
"""
return self.r, self.g, self.b
def as_bgr(self) -> Tuple[int, int, int]:
"""
Returns the color as a tuple of integers in the BGR format
Returns the color as a BGR tuple.
:return: Tuple[int, int, int] : The color in the BGR format
Returns:
Tuple[int, int, int]: BGR tuple.
Example:
```python
import supervision as sv
sv.Color(r=255, g=255, b=0).as_bgr()
# (0, 255, 255)
```
"""
return self.b, self.g, self.r
@classproperty
def WHITE(cls):
return Color.from_hex("#FFFFFF")
@classproperty
def BLACK(cls):
return Color.from_hex("#000000")
@classproperty
def RED(cls):
return Color.from_hex("#FF0000")
@classproperty
def GREEN(cls):
return Color.from_hex("#00FF00")
@classproperty
def BLUE(cls):
return Color.from_hex("#0000FF")
@classproperty
def YELLOW(cls):
return Color.from_hex("#FFFF00")
@classproperty
def ROBOFLOW(cls):
return Color.from_hex("#A351FB")
@classmethod
@deprecated(
"`Color.white()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.WHITE` instead."
)
def white(cls) -> Color:
return Color.from_hex(color_hex="#ffffff")
@classmethod
@deprecated(
"`Color.black()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.BLACK` instead."
)
def black(cls) -> Color:
return Color.from_hex(color_hex="#000000")
@classmethod
@deprecated(
"`Color.red()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.RED` instead."
)
def red(cls) -> Color:
return Color.from_hex(color_hex="#ff0000")
@classmethod
@deprecated(
"`Color.green()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.GREEN` instead."
)
def green(cls) -> Color:
return Color.from_hex(color_hex="#00ff00")
@classmethod
@deprecated(
"`Color.blue()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.BLUE` instead."
)
def blue(cls) -> Color:
return Color.from_hex(color_hex="#0000ff")
@@ -97,35 +248,144 @@ class Color:
class ColorPalette:
colors: List[Color]
@classproperty
def DEFAULT(cls) -> ColorPalette:
"""
Returns a default color palette.
Returns:
ColorPalette: A ColorPalette instance with default colors.
Example:
```python
import supervision as sv
sv.ColorPalette.DEFAULT
# ColorPalette(colors=[Color(r=255, g=64, b=64), Color(r=255, g=161, b=160), ...])
```
![default-color-palette](https://media.roboflow.com/
supervision-annotator-examples/default-color-palette.png)
""" # noqa: E501 // docs
return ColorPalette.from_hex(color_hex_list=DEFAULT_COLOR_PALETTE)
@classproperty
def ROBOFLOW(cls) -> ColorPalette:
"""
Returns a Roboflow color palette.
Returns:
ColorPalette: A ColorPalette instance with Roboflow colors.
Example:
```python
import supervision as sv
sv.ColorPalette.ROBOFLOW
# ColorPalette(colors=[Color(r=194, g=141, b=252), Color(r=163, g=81, b=251), ...])
```
![roboflow-color-palette](https://media.roboflow.com/
supervision-annotator-examples/roboflow-color-palette.png)
""" # noqa: E501 // docs
return ColorPalette.from_hex(color_hex_list=ROBOFLOW_COLOR_PALETTE)
@classproperty
def LEGACY(cls) -> ColorPalette:
return ColorPalette.from_hex(color_hex_list=LEGACY_COLOR_PALETTE)
@classmethod
@deprecated(
"`ColorPalette.default()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.DEFAULT` instead."
)
def default(cls) -> ColorPalette:
"""
Returns a default color palette.
Returns:
ColorPalette: A ColorPalette instance with default colors.
Example:
```python
import supervision as sv
sv.ColorPalette.default()
# ColorPalette(colors=[Color(r=255, g=64, b=64), Color(r=255, g=161, b=160), ...])
```
""" # noqa: E501 // docs
return ColorPalette.from_hex(color_hex_list=DEFAULT_COLOR_PALETTE)
@classmethod
def from_hex(cls, color_hex_list: List[str]):
def from_hex(cls, color_hex_list: List[str]) -> ColorPalette:
"""
Creates a ColorPalette instance from a list of color hex strings
Create a ColorPalette instance from a list of hex strings.
:param color_hex_list: List[str] : A list of color hex strings in the
format of "fff", "ffffff", "#fff", or "#ffffff"
:return: ColorPalette : A ColorPalette instance representing the color palette
Args:
color_hex_list (List[str]): List of color hex strings.
Returns:
ColorPalette: A ColorPalette instance.
Example:
color_palette = ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
```python
import supervision as sv
sv.ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
# ColorPalette(colors=[Color(r=255, g=0, b=0), Color(r=0, g=255, b=0), ...])
```
"""
colors = [Color.from_hex(color_hex) for color_hex in color_hex_list]
return cls(colors)
def by_idx(self, idx: int) -> Color:
@classmethod
def from_matplotlib(cls, palette_name: str, color_count: int) -> ColorPalette:
"""
Returns the color at a given index in the color palette.
Create a ColorPalette instance from a Matplotlib color palette.
:param idx: int : The index of the color in the color palette
:return: Color : The color at the given index
Args:
palette_name (str): Name of the Matplotlib palette.
color_count (int): Number of colors to sample from the palette.
Returns:
ColorPalette: A ColorPalette instance.
Example:
color_palette = ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
color = color_palette.by_idx(1)
```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), ...])
```
![visualized_color_palette](https://media.roboflow.com/
supervision-annotator-examples/visualized_color_palette.png)
""" # noqa: E501 // docs
mpl_palette = plt.get_cmap(palette_name, color_count)
colors = [
Color(int(r * 255), int(g * 255), int(b * 255))
for r, g, b, _ in mpl_palette.colors
]
return cls(colors)
def by_idx(self, idx: int) -> Color:
"""
Return the color at a given index in the palette.
Args:
idx (int): Index of the color in the palette.
Returns:
Color: Color at the given index.
Example:
```python
import supervision as sv
color_palette = sv.ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
color_palette.by_idx(1)
# Color(r=0, g=255, b=0)
```
"""
if idx < 0:
raise ValueError("idx argument should not be negative")
+108 -5
View File
@@ -1,4 +1,5 @@
from typing import Optional
import os
from typing import Optional, Tuple, Union
import cv2
import numpy as np
@@ -104,7 +105,7 @@ def draw_text(
scene: np.ndarray,
text: str,
text_anchor: Point,
text_color: Color = Color.black(),
text_color: Color = Color.BLACK,
text_scale: float = 0.5,
text_thickness: int = 1,
text_padding: int = 10,
@@ -134,9 +135,11 @@ def draw_text(
Examples:
```python
>>> scene = np.zeros((100, 100, 3), dtype=np.uint8)
>>> text_anchor = Point(x=50, y=50)
>>> scene = draw_text(scene=scene, text="Hello, world!",text_anchor=text_anchor)
import numpy as np
scene = np.zeros((100, 100, 3), dtype=np.uint8)
text_anchor = Point(x=50, y=50)
scene = draw_text(scene=scene, text="Hello, world!",text_anchor=text_anchor)
```
"""
text_width, text_height = cv2.getTextSize(
@@ -168,3 +171,103 @@ def draw_text(
lineType=cv2.LINE_AA,
)
return scene
def draw_image(
scene: np.ndarray, image: Union[str, np.ndarray], opacity: float, rect: Rect
) -> np.ndarray:
"""
Draws an image onto a given scene with specified opacity and dimensions.
Args:
scene (np.ndarray): Background image where the new image will be drawn.
image (Union[str, np.ndarray]): Image to draw.
opacity (float): Opacity of the image to be drawn.
rect (Rect): Rectangle specifying where to draw the image.
Returns:
np.ndarray: The updated scene.
Raises:
FileNotFoundError: If the image path does not exist.
ValueError: For invalid opacity or rectangle dimensions.
"""
# Validate and load image
if isinstance(image, str):
if not os.path.exists(image):
raise FileNotFoundError(f"Image path ('{image}') does not exist.")
image = cv2.imread(image, cv2.IMREAD_UNCHANGED)
# Validate opacity
if not 0.0 <= opacity <= 1.0:
raise ValueError("Opacity must be between 0.0 and 1.0.")
# Validate rectangle dimensions
if (
rect.x < 0
or rect.y < 0
or rect.x + rect.width > scene.shape[1]
or rect.y + rect.height > scene.shape[0]
):
raise ValueError("Invalid rectangle dimensions.")
# Resize and isolate alpha channel
image = cv2.resize(image, (rect.width, rect.height))
alpha_channel = (
image[:, :, 3]
if image.shape[2] == 4
else np.ones((rect.height, rect.width), dtype=image.dtype) * 255
)
alpha_scaled = cv2.convertScaleAbs(alpha_channel * opacity)
# Perform blending
scene_roi = scene[rect.y : rect.y + rect.height, rect.x : rect.x + rect.width]
alpha_float = alpha_scaled.astype(np.float32) / 255.0
blended_roi = cv2.convertScaleAbs(
(1 - alpha_float[..., np.newaxis]) * scene_roi
+ alpha_float[..., np.newaxis] * image[:, :, :3]
)
# Update the scene
scene[rect.y : rect.y + rect.height, rect.x : rect.x + rect.width] = blended_roi
return scene
def calculate_dynamic_text_scale(resolution_wh: Tuple[int, int]) -> float:
"""
Calculate a dynamic font scale based on the resolution of an image.
Parameters:
resolution_wh (Tuple[int, int]): A tuple representing the width and height
of the image.
Returns:
float: The calculated font scale factor.
"""
return min(resolution_wh) * 1e-3
def calculate_dynamic_line_thickness(resolution_wh: Tuple[int, int]) -> int:
"""
Calculate a dynamic line thickness based on the resolution of an image.
Parameters:
resolution_wh (Tuple[int, int]): A tuple representing the width and height
of the image.
Returns:
int: The calculated line thickness in pixels.
"""
min_dimension = min(resolution_wh)
if min_dimension < 480:
return 2
if min_dimension < 720:
return 2
if min_dimension < 1080:
return 2
if min_dimension < 2160:
return 4
else:
return 4
+34 -7
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from math import sqrt
from typing import Tuple
@@ -19,6 +20,7 @@ class Position(Enum):
BOTTOM_LEFT = "BOTTOM_LEFT"
BOTTOM_CENTER = "BOTTOM_CENTER"
BOTTOM_RIGHT = "BOTTOM_RIGHT"
CENTER_OF_MASS = "CENTER_OF_MASS"
@classmethod
def list(cls):
@@ -42,13 +44,38 @@ class Vector:
start: Point
end: Point
def is_in(self, point: Point) -> bool:
v1 = Vector(self.start, self.end)
v2 = Vector(self.start, point)
cross_product = (v1.end.x - v1.start.x) * (v2.end.y - v2.start.y) - (
v1.end.y - v1.start.y
) * (v2.end.x - v2.start.x)
return cross_product < 0
@property
def magnitude(self) -> float:
"""
Calculate the magnitude (length) of the vector.
Returns:
float: The magnitude of the vector.
"""
dx = self.end.x - self.start.x
dy = self.end.y - self.start.y
return sqrt(dx**2 + dy**2)
def cross_product(self, point: Point) -> float:
"""
Calculate the 2D cross product (also known as the vector product or outer
product) of the vector and a point, treated as vectors in 2D space.
Args:
point (Point): The point to be evaluated, treated as the endpoint of a
vector originating from the 'start' of the main vector.
Returns:
float: The scalar value of the cross product. It is positive if 'point'
lies to the left of the vector (when moving from 'start' to 'end'),
negative if it lies to the right, and 0 if it is collinear with the
vector.
"""
dx_vector = self.end.x - self.start.x
dy_vector = self.end.y - self.start.y
dx_point = point.x - self.start.x
dy_point = point.y - self.start.y
return (dx_vector * dy_point) - (dy_vector * dx_point)
@dataclass
+4 -3
View File
@@ -22,10 +22,11 @@ def get_polygon_center(polygon: np.ndarray) -> Point:
Examples:
```python
>>> from supervision.geometry.utils import get_polygon_center
from supervision.geometry.utils import get_polygon_center
import numpy as np
>>> vertices = np.array([[0, 0], [0, 1], [1, 1], [1, 0]])
>>> get_center(vertices)
vertices = np.array([[0, 0], [0, 1], [1, 1], [1, 0]])
get_center(vertices)
Point(x=0.5, y=0.5)
```
"""
+135 -133
View File
@@ -116,31 +116,31 @@ class ConfusionMatrix:
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> targets = [
... sv.Detections(...),
... sv.Detections(...)
... ]
targets = [
sv.Detections(...),
sv.Detections(...)
]
>>> predictions = [
... sv.Detections(...),
... sv.Detections(...)
... ]
predictions = [
sv.Detections(...),
sv.Detections(...)
]
>>> confusion_matrix = sv.ConfusionMatrix.from_detections(
... predictions=predictions,
... targets=target,
... classes=['person', ...]
... )
confusion_matrix = sv.ConfusionMatrix.from_detections(
predictions=predictions,
targets=target,
classes=['person', ...]
)
>>> confusion_matrix.matrix
array([
[0., 0., 0., 0.],
[0., 1., 0., 1.],
[0., 1., 1., 0.],
[1., 1., 0., 0.]
])
print(confusion_matrix.matrix)
# np.array([
# [0., 0., 0., 0.],
# [0., 1., 0., 1.],
# [0., 1., 1., 0.],
# [1., 1., 0., 0.]
# ])
```
"""
@@ -191,46 +191,47 @@ class ConfusionMatrix:
Example:
```python
>>> import supervision as sv
import supervision as sv
import numpy as np
>>> targets = (
... [
... array(
... [
... [0.0, 0.0, 3.0, 3.0, 1],
... [2.0, 2.0, 5.0, 5.0, 1],
... [6.0, 1.0, 8.0, 3.0, 2],
... ]
... ),
... array([1.0, 1.0, 2.0, 2.0, 2]),
... ]
... )
targets = (
[
np.array(
[
[0.0, 0.0, 3.0, 3.0, 1],
[2.0, 2.0, 5.0, 5.0, 1],
[6.0, 1.0, 8.0, 3.0, 2],
]
),
np.array([1.0, 1.0, 2.0, 2.0, 2]),
]
)
>>> predictions = [
... array(
... [
... [0.0, 0.0, 3.0, 3.0, 1, 0.9],
... [0.1, 0.1, 3.0, 3.0, 0, 0.9],
... [6.0, 1.0, 8.0, 3.0, 1, 0.8],
... [1.0, 6.0, 2.0, 7.0, 1, 0.8],
... ]
... ),
... array([[1.0, 1.0, 2.0, 2.0, 2, 0.8]])
... ]
predictions = [
np.array(
[
[0.0, 0.0, 3.0, 3.0, 1, 0.9],
[0.1, 0.1, 3.0, 3.0, 0, 0.9],
[6.0, 1.0, 8.0, 3.0, 1, 0.8],
[1.0, 6.0, 2.0, 7.0, 1, 0.8],
]
),
np.array([[1.0, 1.0, 2.0, 2.0, 2, 0.8]])
]
>>> confusion_matrix = sv.ConfusionMatrix.from_tensors(
... predictions=predictions,
... targets=targets,
... classes=['person', ...]
... )
confusion_matrix = sv.ConfusionMatrix.from_tensors(
predictions=predictions,
targets=targets,
classes=['person', ...]
)
>>> confusion_matrix.matrix
array([
[0., 0., 0., 0.],
[0., 1., 0., 1.],
[0., 1., 1., 0.],
[1., 1., 0., 0.]
])
print(confusion_matrix.matrix)
# np.array([
# [0., 0., 0., 0.],
# [0., 1., 0., 1.],
# [0., 1., 1., 0.],
# [1., 1., 0., 0.]
# ])
```
"""
validate_input_tensors(predictions, targets)
@@ -365,28 +366,28 @@ class ConfusionMatrix:
Example:
```python
>>> import supervision as sv
>>> from ultralytics import YOLO
import supervision as sv
from ultralytics import YOLO
>>> dataset = sv.DetectionDataset.from_yolo(...)
dataset = sv.DetectionDataset.from_yolo(...)
>>> model = YOLO(...)
>>> def callback(image: np.ndarray) -> sv.Detections:
... result = model(image)[0]
... return sv.Detections.from_ultralytics(result)
model = YOLO(...)
def callback(image: np.ndarray) -> sv.Detections:
result = model(image)[0]
return sv.Detections.from_ultralytics(result)
>>> confusion_matrix = sv.ConfusionMatrix.benchmark(
... dataset = dataset,
... callback = callback
... )
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.]
])
print(confusion_matrix.matrix)
# np.array([
# [0., 0., 0., 0.],
# [0., 1., 0., 1.],
# [0., 1., 1., 0.],
# [1., 1., 0., 0.]
# ])
```
"""
predictions, targets = [], []
@@ -532,25 +533,25 @@ class MeanAveragePrecision:
Example:
```python
>>> import supervision as sv
import supervision as sv
>>> targets = [
... sv.Detections(...),
... sv.Detections(...)
... ]
targets = [
sv.Detections(...),
sv.Detections(...)
]
>>> predictions = [
... sv.Detections(...),
... sv.Detections(...)
... ]
predictions = [
sv.Detections(...),
sv.Detections(...)
]
>>> mean_average_precision = sv.MeanAveragePrecision.from_detections(
... predictions=predictions,
... targets=target,
... )
mean_average_precision = sv.MeanAveragePrecision.from_detections(
predictions=predictions,
targets=target,
)
>>> mean_average_precison.map50_95
0.2899
print(mean_average_precison.map50_95)
# 0.2899
```
"""
prediction_tensors = []
@@ -583,23 +584,23 @@ class MeanAveragePrecision:
Example:
```python
>>> import supervision as sv
>>> from ultralytics import YOLO
import supervision as sv
from ultralytics import YOLO
>>> dataset = sv.DetectionDataset.from_yolo(...)
dataset = sv.DetectionDataset.from_yolo(...)
>>> model = YOLO(...)
>>> def callback(image: np.ndarray) -> sv.Detections:
... result = model(image)[0]
... return sv.Detections.from_ultralytics(result)
model = YOLO(...)
def callback(image: np.ndarray) -> sv.Detections:
result = model(image)[0]
return sv.Detections.from_ultralytics(result)
>>> mean_average_precision = sv.MeanAveragePrecision.benchmark(
... dataset = dataset,
... callback = callback
... )
mean_average_precision = sv.MeanAveragePrecision.benchmark(
dataset = dataset,
callback = callback
)
>>> mean_average_precision.map50_95
0.433
print(mean_average_precision.map50_95)
# 0.433
```
"""
predictions, targets = [], []
@@ -637,40 +638,41 @@ class MeanAveragePrecision:
Example:
```python
>>> import supervision as sv
import supervision as sv
import numpy as np
>>> targets = (
... [
... array(
... [
... [0.0, 0.0, 3.0, 3.0, 1],
... [2.0, 2.0, 5.0, 5.0, 1],
... [6.0, 1.0, 8.0, 3.0, 2],
... ]
... ),
... array([1.0, 1.0, 2.0, 2.0, 2]),
... ]
... )
targets = (
[
np.array(
[
[0.0, 0.0, 3.0, 3.0, 1],
[2.0, 2.0, 5.0, 5.0, 1],
[6.0, 1.0, 8.0, 3.0, 2],
]
),
np.array([[1.0, 1.0, 2.0, 2.0, 2]]),
]
)
>>> predictions = [
... array(
... [
... [0.0, 0.0, 3.0, 3.0, 1, 0.9],
... [0.1, 0.1, 3.0, 3.0, 0, 0.9],
... [6.0, 1.0, 8.0, 3.0, 1, 0.8],
... [1.0, 6.0, 2.0, 7.0, 1, 0.8],
... ]
... ),
... array([[1.0, 1.0, 2.0, 2.0, 2, 0.8]])
... ]
predictions = [
np.array(
[
[0.0, 0.0, 3.0, 3.0, 1, 0.9],
[0.1, 0.1, 3.0, 3.0, 0, 0.9],
[6.0, 1.0, 8.0, 3.0, 1, 0.8],
[1.0, 6.0, 2.0, 7.0, 1, 0.8],
]
),
np.array([[1.0, 1.0, 2.0, 2.0, 2, 0.8]])
]
>>> mean_average_precison = sv.MeanAveragePrecision.from_tensors(
... predictions=predictions,
... targets=targets,
... )
mean_average_precison = sv.MeanAveragePrecision.from_tensors(
predictions=predictions,
targets=targets,
)
>>> mean_average_precison.map50_95
0.2899
print(mean_average_precison.map50_95)
# 0.6649
```
"""
validate_input_tensors(predictions, targets)

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