Compare commits

..
334 Commits
Author SHA1 Message Date
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
abhishek7kalra fe8a8260dc change return type from list to nparray 2023-10-15 19:06:18 +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 4baf570b28 docs(fix): 📓 poetry env typo fix 2023-10-14 01:12:16 +03:00
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
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
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
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
Piotr Skalski 1bddf26f34 Merge pull request #404 from roboflow/develop
`supervision-0.15.0` release
2023-10-05 09:23:31 +02:00
SkalskiP 73ed3f5f5e 👊 bump develop version to 0.15.0 2023-10-05 09:21:05 +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
SkalskiP 88e7fb76d2 Fixed link targeting in changelog documentation. 2023-10-04 23:57:03 +02:00
Piotr Skalski 09c5407347 Merge pull request #410 from roboflow/feature/blur-annotator-docs-update
Refactor BlurAnnotator class and update documentation
2023-10-04 23:54:48 +02:00
pre-commit-ci[bot] bfcf6469d4 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-04 21:52:50 +00:00
SkalskiP ec72f81749 Refactor BlurAnnotator class and update documentation 2023-10-04 23:50:47 +02:00
Piotr Skalski 3a52f7b082 Merge pull request #405 from Rajarshi-Misra/new1
Create sv.BlurAnnotator #395
2023-10-04 23:29:26 +02:00
SkalskiP 5efb3e2df1 👊 bump develop version to 0.15.0rc3 2023-10-04 19:43:03 +02:00
SkalskiP 6e33cb04ca 🪵 supervision-0.15.0 changelog.md update 2023-10-04 19:35:01 +02:00
Rajarshi-Misra 2455ef7cfe Merge branch 'roboflow:develop' into new1 2023-10-04 22:24:53 +05:30
Rajarshi-Misra 1d0ffeba72 Comments corrected 2023-10-04 22:23:54 +05:30
Piotr Skalski 55d14cf33e Merge pull request #407 from roboflow/feature/color_map_strategy_support_for_trace_annotator
Add color mapping strategy to InferenceSlicer
2023-10-04 18:49:45 +02:00
pre-commit-ci[bot] a66d835a57 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-04 16:37:40 +00:00
SkalskiP 440be5d416 Add color mapping strategy to InferenceSlicer
Added a new argument, 'color_map' in InferenceSlicer to provide more options for color coding while annotating. This includes mapping colors by 'index', 'class' or 'track'. Also refactored the way colors are resolved by separating the responsibility into a new function 'resolve_color_idx' and 'resolve_color'.
2023-10-04 18:36:30 +02:00
Hardik Dava 4fd1ba4dd3 Update var type 2023-10-04 18:34:51 +02:00
Piotr Skalski 61108048e1 Merge pull request #361 from roboflow/add-concurrent-slicer
Add concurrent processing for `sv.InferenceSlicer`
2023-10-04 18:17:52 +02:00
pre-commit-ci[bot] a0b64342ca fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-04 16:17:35 +00:00
Rajarshi-Misra 7cf593b55d Replaced with blur filter 2023-10-04 21:47:24 +05:30
SkalskiP 1c1936e411 Refactor args description in InferenceSlicer 2023-10-04 18:15:08 +02:00
pre-commit-ci[bot] 331ccb8dde fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-04 16:09:38 +00:00
Rajarshi-Misra 7366ba9036 Error resolved 2023-10-04 21:38:44 +05:30
pre-commit-ci[bot] 9d5e53030a fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-04 14:25:37 +00:00
Piotr Skalski d67fa3ae9b Merge branch 'develop' into new1 2023-10-04 16:24:13 +02:00
Piotr Skalski 10ad27d726 Merge pull request #406 from roboflow/feature/annotators-refactor-before-0.15.0-release
Refactor TraceAnnotator to separate utility class
2023-10-04 16:18:49 +02:00
SkalskiP 8511bbb762 Add Tracker ID warning and image to TraceAnnotator doc
Added a warning about the requirement of `tracker_id` for TraceAnnotator in the `core.py`. Also, included an example image in the TraceAnnotator initialization for better understanding in both `core.py` and `annotators.md`.
2023-10-04 16:15:38 +02:00
SkalskiP 14388e56a2 Merge remote-tracking branch 'origin/feature/annotators-refactor-before-0.15.0-release' into feature/annotators-refactor-before-0.15.0-release 2023-10-04 15:35:17 +02:00
SkalskiP 1eb74ed88a Add TraceAnnotator description to the documentation
The documentation has been updated to include the `TraceAnnotator` class.
2023-10-04 15:35:07 +02:00
pre-commit-ci[bot] 87d830d3a1 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-04 13:31:17 +00:00
SkalskiP d7a5624d60 Refactor TraceAnnotator to separate utility class 2023-10-04 15:28:00 +02:00
Rajarshi-Misra d3c71c2119 Merge branch 'roboflow:develop' into new1 2023-10-04 18:01:13 +05:30
Rajarshi-Misra 9ad5e50ae9 Addition of gaussian blur filter 2023-10-04 17:59:03 +05:30
Piotr Skalski 67fa66c7e7 Merge pull request #399 from akashAD98/update_detection_sv
Remove class list dependency for roboflow to detection conversion
2023-10-04 12:08:04 +02:00
dependabot[bot] 492f033882 chore(deps): bump pillow from 9.5.0 to 10.0.1 (#403)
Bumps [pillow](https://github.com/python-pillow/Pillow) from 9.5.0 to 10.0.1.
- [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/9.5.0...10.0.1)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-04 13:07:50 +03:00
SkalskiP e911516180 Change prediction class handling from text to ids
Updated the prediction parsing logic in supervision/detection/utils.py and supervision/detection/core.py to use 'class_id' instead of 'class' names. Adapted tests in test/detection/test_utils.py accordingly to reflect the same change.
2023-10-04 10:44:49 +02:00
pre-commit-ci[bot] ed30ef68af fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-03 17:47:44 +00:00
Hardik Dava fefd273a0f removing class list from test inputs 2023-10-03 19:45:38 +02:00
pre-commit-ci[bot] 8746dd3d0e fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-03 17:34:30 +00:00
Hardik Dava 7cb57c9cc9 Fixing int conversion bug 2023-10-03 19:33:56 +02:00
James ddc036ea3a Update CODE_OF_CONDUCT.md (#400) 2023-10-03 19:40:56 +03:00
pre-commit-ci[bot] c83959bb16 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-10-03 16:18:29 +00:00
Akash A Desai 4f513ce275 Update core.py
remoed class_list arg from core.py file
2023-10-03 21:41:13 +05:30
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
Piotr Skalski 6f30c87612 Merge pull request #392 from roboflow/docs/documentation-refactoring
Refactor documentation structure and improve annotator details
2023-10-03 11:53:09 +02:00
SkalskiP 93a8110908 Refactor documentation structure and improve annotator details
Update the file and section structure of the project documentation for better readability. Removed 'annotate.md' and replaced it with an expanded 'annotators.md'. The new document provides examples of each annotator and includes preview images for better understanding. The API reference structure was flattened for simplicity and related documents 'core.py' and 'mkdocs.yml' were updated accordingly. The core tracker and dataset documents were renamed for consistency.
2023-10-03 11:38:28 +02:00
dependabot[bot] 410b7eb4fc chore(deps-dev): bump urllib3 from 2.0.4 to 2.0.6 (#389)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.4 to 2.0.6.
- [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.4...2.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-03 12:07:45 +03:00
Piotr Skalski e6e1397f56 Merge pull request #386 from onuralpszr/feature/circle_annotator
feat(annotator): 🚀 introduce circle annotator
2023-10-02 23:56:24 +02:00
Piotr Skalski 0ca9a3ecdf Merge pull request #384 from roboflow/code-of-conduct
docs: 📝 code of conduct added
2023-10-02 23:54:36 +02:00
pre-commit-ci[bot] c5016bbd8f chore(pre_commit): ⬆ pre_commit autoupdate (#388)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.291 → v0.0.292](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.291...v0.0.292)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-03 00:16:20 +03:00
Onuralp SEZER 9fbd0ddf62 docs(annotator): 📝 circle annotator example picture added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-03 00:03:20 +03:00
Onuralp SEZER a630870968 feat(annotator): 🚀 introduce circle annotator
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-10-01 20:51:46 +03:00
Onuralp SEZER 06416607cc docs: 📝 code of conduct added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-29 14:54:56 +03:00
SkalskiP 1b449294c4 👊 bump develop version to 0.15.0rc2 2023-09-29 13:46:39 +02:00
Onuralp SEZER 36f95d060d Merge pull request #170 from roboflow/feature/redesigned_annotators
redesigned annotators
2023-09-29 14:36:43 +03:00
Onuralp SEZER 07c344e050 fix: 🐛 add missing TraceAnnotator (traffic_analysis fix) and sv version adjusted
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-29 13:25:26 +03:00
pre-commit-ci[bot] f3bdb6efa2 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 21:55:12 +00:00
SkalskiP f4f9e7ddc7 ready for review 2023-09-28 23:54:34 +02:00
pre-commit-ci[bot] 53f2b4fd45 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 21:24:53 +00:00
SkalskiP c7582f7c07 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 23:24:39 +02:00
SkalskiP 3e8906d830 📘 docs updates for LabelAnnotator 2023-09-28 23:24:22 +02:00
pre-commit-ci[bot] 6521f9f4ed fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 19:47:18 +00:00
SkalskiP 560a35b75f 🧪 test LabelAnnotator supporting more Position values 2023-09-28 21:46:02 +02:00
pre-commit-ci[bot] 405a4c73f9 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 16:16:11 +00:00
SkalskiP 87fd10c366 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 18:15:57 +02:00
SkalskiP 8141cb357f Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 18:15:45 +02:00
SkalskiP 87fb336eb6 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 18:13:32 +02:00
SkalskiP 28d279bec3 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 18:12:43 +02:00
pre-commit-ci[bot] 1b0bcea5a6 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 16:10:18 +00:00
SkalskiP 507e000bca Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 18:08:45 +02:00
SkalskiP f7bf766a60 🧪 Test of LabelAnnotator alternative annotate method implementation. 2023-09-28 18:08:01 +02:00
pre-commit-ci[bot] 1e0f18f792 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 15:11:28 +00:00
SkalskiP be5c1b1aa1 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 17:11:14 +02:00
SkalskiP c35a7714d2 🧪 Test of BoxCornerAnnotator alternative annotate method implementation. 2023-09-28 17:11:06 +02:00
pre-commit-ci[bot] a8cc5a68bb fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 14:48:53 +00:00
SkalskiP de4056192e 🛠️ Refactor of BoxCornerAnnotator docs and annotate method implementation. 2023-09-28 16:48:03 +02:00
SkalskiP d337a03d28 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 16:27:07 +02:00
SkalskiP 00b67588d8 🛠️ EllipseAnnotator.end_angle fix 2023-09-28 16:25:35 +02:00
pre-commit-ci[bot] e10e0f21df fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 14:14:41 +00:00
SkalskiP 4fb6760d2c Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 16:14:28 +02:00
SkalskiP de7ed5e115 🔨 EllipseAnnotator refactor. Changes in annotate method + new docstrings. 2023-09-28 16:14:17 +02:00
pre-commit-ci[bot] d929b86c9f fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 13:52:31 +00:00
SkalskiP 0b1627f835 Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 15:51:06 +02:00
SkalskiP 20b1b21774 🧹 Removed old MaskAnnotator implementation as it is no longer used. Moved ColorMap, resolve_color_idx, resolve_color and BaseAnnotator to supervision/annotators/base. Removed BoxMaskAnnotator as it can be achieved by BoundingBoxAnnotator and MaskAnnotator composition. 2023-09-28 15:50:55 +02:00
pre-commit-ci[bot] e5eaf26137 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 13:37:05 +00:00
SkalskiP be3e67949c Merge remote-tracking branch 'origin/feature/redesigned_annotators' into feature/redesigned_annotators 2023-09-28 15:36:28 +02:00
SkalskiP 2587fdfefd ☝️ updating MaskAnnotator docs and code to be consistent with BoundingBoxAnnotator 2023-09-28 15:36:18 +02:00
pre-commit-ci[bot] 08a88a8c0c fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 11:47:28 +00:00
SkalskiP 181c0b833b 🔨 small names refactor 2023-09-28 13:46:52 +02:00
pre-commit-ci[bot] 11601e3f2d fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-28 10:14:38 +00:00
SkalskiP 1b8ff617c3 📘 docs updates for Position and get_anchor_coordinates 2023-09-28 12:13:52 +02:00
SkalskiP 5bc83bf6cc Merge branch 'develop' into feature/redesigned_annotators 2023-09-27 12:08:07 +02:00
fatihandpre-commit-ci[bot] dd80753b2b add sahi paper url into docstring (#382)
* add sahi paper url into docstring
* fix(pre_commit): 🎨 auto format pre-commit hooks

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-27 00:59:57 +03:00
Piotr Skalski b2bb69bebb Merge pull request #381 from Killua7362/utils-fix
Adding Fourcc codecs option to VideoSink
2023-09-26 14:32:44 +02:00
pre-commit-ci[bot] 9c081b0e11 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-26 05:40:22 +00:00
Akshay 7f613c6d27 Merge branch 'utils-fix' of https://github.com/Killua7362/supervision into utils-fix 2023-09-26 08:40:01 +03:00
Akshay 9736eba9e6 FIX: Added type error exception in videosink 2023-09-26 08:38:46 +03:00
pre-commit-ci[bot] 53dfeac19b fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-26 05:25:00 +00:00
Akshay 5c25e58e39 Added docstrings for codec 2023-09-26 08:22:07 +03:00
Akshay 52949f2fd1 Support for all the codes 2023-09-26 08:12:18 +03:00
pre-commit-ci[bot] 56c511b5d8 chore(pre_commit): ⬆ pre_commit autoupdate (#379)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.290 → v0.0.291](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.290...v0.0.291)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-26 00:20:59 +03:00
Piotr Skalski 62014186a2 Update README.md with latest supervision YouTube tutorial 2023-09-22 13:43:56 +02:00
dependabot[bot] 6cd7cf0209 Bump cryptography from 41.0.3 to 41.0.4 (#375)
Bumps [cryptography](https://github.com/pyca/cryptography) from 41.0.3 to 41.0.4.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/41.0.3...41.0.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-22 10:17:28 +03:00
Onuralp SEZER a39c92016f docs(example): 📝 example LabelAnnotator doc fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-21 15:45:04 +03:00
Onuralp SEZER 4e88e26d91 chore(formatting): pre-commit fixes
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-21 15:43:07 +03:00
pre-commit-ci[bot] 484e53324e fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-21 12:36:21 +00:00
Onuralp SEZER e5c4d8e3b9 docs(example): 📝 Update tracking example with new annotators
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-21 15:34:17 +03:00
Onuralp SEZER 52ef3fadcb fix(redefinition): 🐞 fix redefinition for MaskAnnotator TraceAnnotator
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-21 14:46:35 +03:00
pre-commit-ci[bot] 472ddd8d0e fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-21 11:35:41 +00:00
Onuralp SEZER 90b23430d2 Merge branch 'develop' into feature/redesigned_annotators
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-21 14:35:24 +03:00
pre-commit-ci[bot] e91f0cb496 chore(pre_commit): ⬆ pre_commit autoupdate (#366)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.288 → v0.0.290](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.288...v0.0.290)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-19 16:34:16 +03:00
pre-commit-ci[bot] fa6238dbc4 chore(pre_commit): ⬆ pre_commit autoupdate (#362)
updates:
- [github.com/psf/black: 23.7.0 → 23.9.1](https://github.com/psf/black/compare/23.7.0...23.9.1)
- [github.com/astral-sh/ruff-pre-commit: v0.0.287 → v0.0.288](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.287...v0.0.288)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-12 00:32:39 +03:00
Onuralp SEZER 1a7306c4ae ci(test): 🔥 removal formatters from test ci (#317)
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-10 23:29:45 +03:00
Onuralp SEZER c6b8fbed31 fix(pre-commit): formatting fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-08 21:29:37 +03:00
Onuralp SEZER b9598f54b6 feat: ✨ control thread worker and set default 1
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-08 15:08:37 +03:00
pre-commit-ci[bot] 21e5d5139c fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-08 12:04:17 +00:00
Onuralp SEZER 8f583404ce fix(import): 📦 import only ThreadPoolExecutor,as_completed
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-09-08 15:03:59 +03:00
pre-commit-ci[bot] bb42753e23 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-08 11:46:17 +00:00
James Gallagher ea0ec29c81 add concurrent processing for inference slicer 2023-09-08 12:43:20 +01:00
Onuralp SEZER 3d4326c79b Merge pull request #349 from onuralpszr/empty_box_checks
fix: 🐛 Empty check for xyxy results for prevent ValueError and return as empty detection
2023-09-05 20:17:17 +03:00
pre-commit-ci[bot] ca212b70c8 chore(pre_commit): ⬆ pre_commit autoupdate (#355)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.286 → v0.0.287](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.286...v0.0.287)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-05 20:15:19 +03:00
Piotr Skalski 0008b33eb1 Add traffic analysis demo to README.md 2023-09-05 17:52:29 +02:00
SkalskiP 77190f287c 📍 Pin supervision==0.15.0rc1 in examples/traffic_analysis 2023-09-04 23:08:12 +02:00
Piotr Skalski 121d4f31bb 👊 supervision version to `0.15.0rc1 in pyproject.toml` 2023-09-04 23:06:02 +02:00
Piotr Skalski 7c97e87e79 Merge pull request #354 from roboflow/example/traffic_analysis
example/traffic_analysis
2023-09-04 23:03:40 +02:00
SkalskiP 9640f1d756 TraceAnnotator documentation 2023-09-04 22:56:42 +02:00
SkalskiP 2419d42224 TraceAnnotator documentation 2023-09-04 22:52:47 +02:00
Piotr Skalski c6517de143 Update README.md 2023-09-04 22:36:26 +02:00
pre-commit-ci[bot] 2706304a73 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-04 20:18:46 +00:00
SkalskiP 8538c26a22 Add TraceAnnotator, refactor traffic analysis code and improve documentation
Introduced TraceAnnotator in the supervision package, refactored traffic analysis script for improved readability, and added quality documentation.
2023-09-04 22:16:37 +02:00
SkalskiP a0c60fe043 Refactor video stream and traffic analysis process
Restructuring the video stream and traffics analysis codes resulted in two new key classes, VideoProcessor, and DetectionsManager. The main aim behind this was to improve code readability and reusability. VideoProcessor class handles video processing as an object, while DetectionsManager is responsible for managing detections and trackings. This change has also led to the removal of the process_frame function, as its functionality is now encapsulated within VideoProcessor class methods. Moreover, the code now identifies zones in and out separately, thereby handling detections more distinctly and efficiently. Lastly, Polygon Zones are no longer differentiated by color.
2023-09-04 17:28:19 +02:00
SkalskiP 01d8b0316c "Improve detection and annotation in the supervision module
The change modifies the polygon zone verification method in `polygon_zone.py` to ensure `self.current_count` always returns an integer, preventing possible type errors in downstream processing. Two classes, `Trace` and `TraceAnnotator`, were added to `annotate.py`, providing functionality for trace annotation during detection. In `script.py`, optimized the trace annotation process by replacing the previous class implementations with the new ones from `annotate.py`, and also cleaned up and simplified polygon zone initiation and frame processing. This provides more efficient and robust video processing and zone-based detection features."
2023-09-03 18:25:28 +02:00
SkalskiP 6356a8ac3d Add Trace and TraceAnnotator classes to traffic_analysis script
Added two new classes to enhance traffic analysis over video frames. Trace class stores the positional information of different objects detected in each video frame for a specified length. TraceAnnotator class uses the information stored in Trace instance to annotate the motion path of detected objects on the video frames. Also, corrected the incorrect numpy import statement in the dependence code.
2023-09-03 17:11:25 +02:00
pre-commit-ci[bot] bbd9a955f8 fix(pre_commit): 🎨 auto format pre-commit hooks 2023-09-02 19:45:43 +00:00
Onuralp SEZER 7b2bcf00ad fix: 🐛 sam xyxy check added
Signed-off-by: Onuralp SEZER <thunderbirdtr@fedoraproject.org>
2023-09-02 22:45:29 +03:00
Onuralp SEZER 775a3f2795 fix: 🐛 cpu().numpy() converts not require empty check
Signed-off-by: Onuralp SEZER <thunderbirdtr@fedoraproject.org>
2023-09-02 22:43:27 +03:00
Onuralp SEZER 5dae02e93e fix: 🐛 deepsparse model_stub to model_path docs fix
Signed-off-by: Onuralp SEZER <thunderbirdtr@fedoraproject.org>
2023-09-02 20:40:35 +03:00
Onuralp SEZER 666427df08 fix: 🐛 empty check for xyxy results for prevent ValueError and return as empty detection
Signed-off-by: Onuralp SEZER <thunderbirdtr@fedoraproject.org>
2023-09-02 20:36:00 +03:00
Hardik Davaandpre-commit-ci[bot] 78411b14b5 fixed empty detections for deepsparse (#348)
* fixed empty detections for deepsparse
* fix(pre_commit): 🎨 auto format pre-commit hooks

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-09-02 20:08:30 +03:00
SkalskiP 69ae5c6cd9 Add traffic analysis script
Introduced a python script for video processing using YOLO and ByteTrack. The script processes videos frame by frame and allows annotation based on model's detections. Additionally, the requirements.txt file was added along with .gitignore to exclude the data/ directory. The requirements file lists the necessary packages for the script to run.
2023-09-01 18:06:09 +02:00
dependabot[bot] 94d08bc9b5 Bump cryptography from 41.0.2 to 41.0.3 (#345)
Bumps [cryptography](https://github.com/pyca/cryptography) from 41.0.2 to 41.0.3.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/41.0.2...41.0.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 12:27:48 +03: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
Piotr Skalski 693465d74d Merge pull request #342 from roboflow/main
Merge pull request #337 from roboflow/develop
2023-08-31 17:54:46 +02:00
Hardik Dava 92413d3cc2 Merge pull request #277 from hardikdava/feature/trace_annotators
tracer in consistent format
2023-08-14 21:20:56 +02: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
Hardik Dava 8b764218eb tracer in consistent format 2023-08-10 10:00:26 +02:00
SkalskiP 117ba2fcc0 🧪 initial API tests 2023-07-24 23:17:21 +02:00
Piotr Skalski 1d28b8ae26 Merge pull request #171 from hardikdava/advanced_box_annotator
cornered box annotator
2023-07-23 20:44:29 +02:00
SkalskiP cc2e08ac72 🖤 make black happy 2023-07-23 20:40:46 +02:00
SkalskiP ba03fefbd8 🧹‍💨 cleanup in progress 2023-07-23 20:39:12 +02:00
SkalskiP 4cd9f05fab 🧪 reformatted tests 2023-07-23 20:08:34 +02:00
SkalskiP 8066125f03 🧹‍💨 clean up 2023-07-23 19:43:51 +02:00
SkalskiP aa772dde8d 🧹‍💨 clean up 2023-07-23 19:42:47 +02:00
Piotr Skalski 1b5e6db196 Merge pull request #159 from Ucag/feature/unicode-label-support
Add unicode label support
2023-07-21 14:13:40 +02:00
hd fc4bb27aa8 removing extra spacing 2023-07-21 12:54:44 +02:00
hd ace6ce363f Tests added for anchor fn 2023-07-21 12:54:19 +02:00
hd f0cef99de7 ready for review 2023-07-21 11:53:44 +02:00
hd c4d296fbc6 Ready for review 2023-07-19 10:58:39 +02:00
hd 9c4555a800 Added extra anchor points calculation 2023-07-19 09:47:49 +02:00
hd 4b423fd402 Fixed typo in annotator 2023-07-07 22:40:30 +02:00
hd 27efbc044d Adding EllipseAnotator and added backward compatibility for box and mask annotator 2023-07-07 19:18:12 +02:00
hd 2a2c259964 🔥 Consistent code style 2023-07-07 09:37:03 +02:00
hd c705d50e74 Marked as ready to review 2023-07-05 15:39:22 +02:00
hd d5b8a3aa1a Adding cornered box annotator and pillow label annotator 2023-07-05 15:01:16 +02:00
hd d9f6c5c73c tracked detection method added along with trackstorage 2023-07-04 20:42:33 +02:00
Hardik Dava 65a93f8287 Merge pull request #2 from hardikdava/redesigned_annotators
updated code
2023-07-04 16:16:53 +02:00
hd 1bcf8346dc updated code 2023-07-04 16:12:30 +02:00
Hardik Dava aba6ff57a9 Merge pull request #1 from hardikdava/redesigned_annotators
Redesigned annotators
2023-07-04 13:47:15 +02:00
hd b5e1342038 Updating refactored annotators 2023-07-04 13:38:10 +02:00
SkalskiP 64d223b76d 🖤 make black happy 2023-07-02 23:28:28 +02:00
SkalskiP 21968e53c6 ✏️initial PR for redesigned annotators 2023-07-02 23:25:43 +02:00
hd 9b77b2a1c6 initial commit for advanced annotator 2023-06-30 18:25:13 +02:00
dong.li ddabe04409 add unicode label support 2023-06-28 09:56:53 +08:00
56 changed files with 3560 additions and 954 deletions
+17
View File
@@ -0,0 +1,17 @@
contourpy==1.1.0 ; python_version >= "3.8" and python_full_version < "3.12.0"
cycler==0.11.0 ; python_version >= "3.8" and python_full_version < "3.12.0"
fonttools==4.41.1 ; python_version >= "3.8" and python_full_version < "3.12.0"
importlib-resources==6.0.0 ; python_version >= "3.8" and python_version < "3.10"
kiwisolver==1.4.4 ; python_version >= "3.8" and python_full_version < "3.12.0"
matplotlib==3.7.2 ; python_version >= "3.8" and python_full_version < "3.12.0"
numpy==1.24.4 ; python_version >= "3.8" and python_version < "3.12"
opencv-python-headless==4.8.0.74 ; python_version >= "3.8" and python_full_version < "3.12.0"
packaging==23.1 ; python_version >= "3.8" and python_full_version < "3.12.0"
pillow==10.0.1 ; python_version >= "3.8" and python_full_version < "3.12.0"
pyparsing==3.0.9 ; python_version >= "3.8" and python_full_version < "3.12.0"
python-dateutil==2.8.2 ; python_version >= "3.8" and python_full_version < "3.12.0"
pyyaml==6.0.1 ; python_version >= "3.8" and python_full_version < "3.12.0"
scipy==1.10.1 ; python_version >= "3.8" and python_version < "3.12"
six==1.16.0 ; python_version >= "3.8" and python_full_version < "3.12.0"
zipp==3.16.2 ; python_version >= "3.8" and python_version < "3.10"
pytest==7.4.0 ; python_version >= "3.8" and python_full_version < "3.12.0"
+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@v6
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 -6
View File
@@ -15,15 +15,18 @@ jobs:
uses: actions/checkout@v3
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
# id based on python version
id: python-setup
with:
python-version: ${{ matrix.python-version }}
- name: 🦾 Install dependencies
check-latest: true
cache: 'pip'
cache-dependency-path: '**/requirements-dev.txt'
- name: 📦 Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .
pip install pytest
pip install isort
pip install flake8
pip install "black==22.3.0"
pip install -r .github/requirements-dev.txt
- name: 🧪 Test
run: "python -m pytest ./test"
+4 -8
View File
@@ -7,7 +7,7 @@ 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
@@ -22,6 +22,7 @@ repos:
- 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
@@ -33,11 +34,6 @@ repos:
# 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
@@ -69,12 +65,12 @@ repos:
- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.9.1
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.286
rev: v0.0.292
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
+134
View File
@@ -0,0 +1,134 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
community-reports@roboflow.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
-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
+24 -11
View File
@@ -19,9 +19,15 @@
[![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>
<a href="https://github.com/roboflow/supervision/issues?q=is%3Aissue+label%3Ahacktoberfest+">
<img width="100%" src="https://media.roboflow.com/open-source/supervision/hacktoberfest-banner-3.png">
</a>
## 👋 hello
**We write your reusable computer vision tools.** Whether you need to load your dataset from your hard drive, draw detections on an image or video, or count how many detections are in a zone. You can count on us! 🤝
@@ -273,19 +279,13 @@ array([
</details>
## 🛠️ built with supervision
Did you build something cool using supervision? [Let us know!](https://github.com/roboflow/supervision/discussions/categories/built-with-supervision)
https://user-images.githubusercontent.com/26109316/207858600-ee862b22-0353-440b-ad85-caa0c4777904.mp4
## 🎬 tutorials
<p align="left">
<a href="https://youtu.be/oEQYStnF2l8" title="Accelerate Image Annotation with SAM and Grounding DINO"><img src="https://github.com/SkalskiP/SkalskiP/assets/26109316/ae1ca38e-40b7-4b35-8582-e8ea5de3806e" alt="Accelerate Image Annotation with SAM and Grounding DINO" width="300px" align="left" /></a>
<a href="https://youtu.be/oEQYStnF2l8" title="Accelerate Image Annotation with SAM and Grounding DINO"><strong>Accelerate Image Annotation with SAM and Grounding DINO</strong></a>
<div><strong>Created: 20 Apr 2023</strong> | <strong>Updated: 20 Apr 2023</strong></div>
<br/> Discover how to speed up your image annotation process using Grounding DINO and Segment Anything Model (SAM). Learn how to convert object detection datasets into instance segmentation datasets, and see the potential of using these models to automatically annotate your datasets for real-time detectors like YOLOv8... </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>
<br/>
@@ -295,6 +295,14 @@ https://user-images.githubusercontent.com/26109316/207858600-ee862b22-0353-440b-
<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>
## 💜 built with supervision
Did you build something cool using supervision? [Let us know!](https://github.com/roboflow/supervision/discussions/categories/built-with-supervision)
https://user-images.githubusercontent.com/26109316/207858600-ee862b22-0353-440b-ad85-caa0c4777904.mp4
https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-60e9c81b3900
## 📚 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.
@@ -303,6 +311,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">
@@ -350,5 +364,4 @@ We love your input! Please see our [contributing guide](https://github.com/robof
</a>
</a>
</div>
</div>
Vendored
+528 -528
View File
File diff suppressed because one or more lines are too long
+321
View File
@@ -0,0 +1,321 @@
=== "BoundingBox"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.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-purple.png){ align=center width="800" }
</div>
=== "BoxCorner"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> corner_annotator = sv.BoxCornerAnnotator()
>>> annotated_frame = corner_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
<div class="result" markdown>
![box-corner-annotator-example](https://media.roboflow.com/supervision-annotator-examples/box-corner-annotator-example-purple.png){ align=center width="800" }
</div>
=== "BoxMask"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> box_mask_annotator = sv.BoxMaskAnnotator()
>>> annotated_frame = box_mask_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
>>> image = ...
>>> detections = sv.Detections(...)
>>> circle_annotator = sv.CircleAnnotator()
>>> annotated_frame = circle_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
<div class="result" markdown>
![circle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/circle-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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>
![circle-annotator-example](https://media.roboflow.com/supervision-annotator-examples/dot-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Ellipse"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> ellipse_annotator = sv.EllipseAnnotator()
>>> annotated_frame = ellipse_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
<div class="result" markdown>
![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ellipse-annotator-example-purple.png){ align=center width="800" }
</div>
=== "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>
![ellipse-annotator-example](https://media.roboflow.com/supervision-annotator-examples/halo-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Mask"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> mask_annotator = sv.MaskAnnotator()
>>> annotated_frame = mask_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
<div class="result" markdown>
![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Label"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.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-purple.png){ align=center width="800" }
</div>
=== "Blur"
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> blur_annotator = sv.BlurAnnotator()
>>> annotated_frame = blur_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
<div class="result" markdown>
![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-purple.png){ align=center width="800" }
</div>
=== "Trace"
```python
>>> import supervision as sv
>>> from ultralytics import YOLO
>>> model = YOLO('yolov8x.pt')
>>> trace_annotator = sv.TraceAnnotator()
>>> video_info = sv.VideoInfo.from_video_path(video_path='...')
>>> frames_generator = get_video_frames_generator(source_path='...')
>>> tracker = sv.ByteTrack()
>>> with sv.VideoSink(target_path='...', video_info=video_info) as sink:
... for frame in frames_generator:
... result = model(frame)[0]
... detections = sv.Detections.from_ultralytics(result)
... detections = tracker.update_with_detections(detections)
... annotated_frame = trace_annotator.annotate(
... scene=frame.copy(),
... detections=detections)
... sink.write_frame(frame=annotated_frame)
```
<div class="result" markdown>
![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example-purple.png){ align=center width="800" }
</div>
=== "HeatMap"
```python
>>> import supervision as sv
>>> from ultralytics import YOLO
>>> model = YOLO('yolov8x.pt')
>>> heat_map_annotator = sv.HeatMapAnnotator()
>>> video_info = sv.VideoInfo.from_video_path(video_path='...')
>>> frames_generator = 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>
![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/heat-map-annotator-example-purple.png){ align=center width="800" }
</div>
## BoundingBoxAnnotator
:::supervision.annotators.core.BoundingBoxAnnotator
## BoxCornerAnnotator
:::supervision.annotators.core.BoxCornerAnnotator
## BoxMaskAnnotator
:::supervision.annotators.core.BoxMaskAnnotator
## CircleAnnotator
:::supervision.annotators.core.CircleAnnotator
## DotAnnotator
:::supervision.annotators.core.DotAnnotator
## EllipseAnnotator
:::supervision.annotators.core.EllipseAnnotator
## HaloAnnotator
:::supervision.annotators.core.HaloAnnotator
## HeatMapAnnotator
:::supervision.annotators.core.HeatMapAnnotator
## MaskAnnotator
:::supervision.annotators.core.MaskAnnotator
## LabelAnnotator
:::supervision.annotators.core.LabelAnnotator
## BlurAnnotator
:::supervision.annotators.core.BlurAnnotator
## TraceAnnotator
:::supervision.annotators.core.TraceAnnotator
## ColorLookup
:::supervision.annotators.utils.ColorLookup
+83
View File
@@ -1,3 +1,86 @@
### 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.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.BoxCornerAnnotator `](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BoxCornerAnnotator) allowing to annotate images and videos with just bounding box corners.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.MaskAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.MaskAnnotator) allowing to annotate images and videos with segmentation masks.
- Added [#170](https://github.com/roboflow/supervision/pull/170): [`sv.EllipseAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.EllipseAnnotator) allowing to annotate images and videos with ellipses (sports game style).
- Added [#386](https://github.com/roboflow/supervision/pull/386): [`sv.CircleAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.CircleAnnotator) allowing to annotate images and videos with circles.
- Added [#354](https://github.com/roboflow/supervision/pull/354): [`sv.TraceAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.TraceAnnotator) allowing to draw path of moving objects on videos.
- Added [#405](https://github.com/roboflow/supervision/pull/405): [`sv.BlurAnnotator`](https://supervision.roboflow.com/annotators/#supervision.annotators.core.BlurAnnotator) allowing to blur objects on images and videos.
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> bounding_box_annotator = sv.BoundingBoxAnnotator()
>>> annotated_frame = bounding_box_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
- Added [#354](https://github.com/roboflow/supervision/pull/354): Supervision usage [example](https://github.com/roboflow/supervision/tree/develop/examples/traffic_analysis). You can now learn how to perform traffic flow analysis with Supervision.
- Changed [#399](https://github.com/roboflow/supervision/pull/399): [`sv.Detections.from_roboflow`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_roboflow) now does not require `class_list` to be specified. The `class_id` value can be extracted directly from the [inference](https://github.com/roboflow/inference) response.
- Changed [#381](https://github.com/roboflow/supervision/pull/381): [`sv.VideoSink`](https://supervision.roboflow.com/utils/video/#videosink) now allows to customize the output codec.
- Changed [#361](https://github.com/roboflow/supervision/pull/361): [`sv.InferenceSlicer`](https://supervision.roboflow.com/detection/tools/inference_slicer/#supervision.detection.tools.inference_slicer.InferenceSlicer) can now operate in multithreading mode.
- Fixed [#348](https://github.com/roboflow/supervision/pull/348): [`sv.Detections.from_deepsparse`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_deepsparse) to allow processing empty [deepsparse](https://github.com/neuralmagic/deepsparse) result object.
### 0.14.0 <small>August 31, 2023</small>
- Added [#282](https://github.com/roboflow/supervision/pull/282): support for SAHI inference technique with [`sv.InferenceSlicer`](https://supervision.roboflow.com/detection/tools/inference_slicer).
-7
View File
@@ -1,7 +0,0 @@
## BoxAnnotator
:::supervision.detection.annotate.BoxAnnotator
## MaskAnnotator
:::supervision.detection.annotate.MaskAnnotator
+3
View File
@@ -0,0 +1,3 @@
## LineZone
:::supervision.detection.line_counter.LineZone
+7
View File
@@ -0,0 +1,7 @@
## Color
:::supervision.draw.color.Color
## ColorPalette
:::supervision.draw.color.ColorPalette
+4
View File
@@ -17,3 +17,7 @@
## draw_text
:::supervision.draw.utils.draw_text
## draw_image
:::supervision.draw.utils.draw_image
+3
View File
@@ -0,0 +1,3 @@
## Position
:::supervision.geometry.core.Position
+78
View File
@@ -0,0 +1,78 @@
With Supervision, you can easily [annotate](https://supervision.roboflow.com/annotators/) predictions obtained from a variety of object detection and segmentation models. This document outlines how to run inference using the [Ultralytics](https://github.com/ultralytics/ultralytics) YOLOv8 model, load these predictions into Supervision, and annotate the image.
## Run Inference
First, you'll need to obtain predictions from your object detection or segmentation model.
```python
import cv2
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
image = cv2.imread("image.jpg")
results = model(image)[0]
```
## Load Predictions into Supervision
Now that we have predictions from a model, we can load them into Supervision. 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
from ultralytics import YOLO
import supervision as sv
model = YOLO("yolov8n.pt")
image = cv2.imread("image.jpg")
results = model(image)[0]
detections = sv.Detections.from_ultralytics(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_roboflow`](https://supervision.roboflow.com/detection/core/#supervision.detection.core.Detections.from_roboflow) ([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.
```python
import cv2
from ultralytics import YOLO
import supervision as sv
model = YOLO("yolov8n.pt")
image = cv2.imread("image.jpg")
results = model(image)[0]
detections = sv.Detections.from_ultralytics(results)
bounding_box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
labels = [
results.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)
```
![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
View File
@@ -0,0 +1 @@
🚧 Page under construction.
@@ -1,6 +1,3 @@
## advanced filtering
The advanced filtering capabilities of the `Detections` class offer users a versatile and efficient way to narrow down
and refine object detections. This section outlines various filtering methods, including filtering by specific class
or a set of classes, confidence, object area, bounding box area, relative area, box dimensions, and designated zones.
+1
View File
@@ -0,0 +1 @@
🚧 Page under construction.
+1
View File
@@ -0,0 +1 @@
🚧 Page under construction.
+2 -1
View File
@@ -46,6 +46,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 +63,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
+4
View File
@@ -6,6 +6,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 @@
## Supervision 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.
| **Title** | **Contributor** |
|:--------------------------------------:|:----------------------------------------:|
| [Tracking](./tracking) | [@SkalskiP](https://github.com/SkalskiP) |
| [Traffic Analysis](./traffic_analysis) | [@SkalskiP](https://github.com/SkalskiP) |
## Guidelines for 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.
+8 -8
View File
@@ -16,7 +16,8 @@ def process_video(
model = YOLO(source_weights_path)
tracker = sv.ByteTrack()
box_annotator = sv.BoxAnnotator()
box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator(classes=model.names)
frame_generator = sv.get_video_frames_generator(source_path=source_video_path)
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
@@ -28,16 +29,15 @@ def process_video(
detections = sv.Detections.from_ultralytics(results)
detections = tracker.update_with_detections(detections)
labels = [
f"#{tracker_id} {model.model.names[class_id]}"
for _, _, _, class_id, tracker_id in detections
]
annotated_frame = box_annotator.annotate(
scene=frame.copy(), detections=detections, labels=labels
scene=frame.copy(), detections=detections
)
sink.write_frame(frame=annotated_frame)
annotated_labeled_frame = label_annotator.annotate(
scene=annotated_frame, detections=detections
)
sink.write_frame(frame=annotated_labeled_frame)
if __name__ == "__main__":
+1
View File
@@ -0,0 +1 @@
data/
+44
View File
@@ -0,0 +1,44 @@
## 👋 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.
https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-60e9c81b3900
## 💻 install
- clone repository and navigate to example directory
```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
```
- install required dependencies
```bash
pip install -r requirements.txt
```
- download `traffic_analysis.pt` and `traffic_analysis.mov` files
```bash
./setup.sh
```
## ⚙️ 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
```
@@ -0,0 +1,4 @@
supervision>=0.15.0rc1
tqdm
ultralytics
gdown
+219
View File
@@ -0,0 +1,219 @@
import argparse
from typing import Dict, List, Set, Tuple
import cv2
import numpy as np
from tqdm import tqdm
from ultralytics import YOLO
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,
source_weights_path: 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 = YOLO(source_weights_path)
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(
frame, verbose=False, conf=self.conf_threshold, iou=self.iou_threshold
)[0]
detections = sv.Detections.from_ultralytics(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 YOLO and ByteTrack"
)
parser.add_argument(
"--source_weights_path",
required=True,
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()
processor = VideoProcessor(
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,
)
processor.process_video()
+17
View File
@@ -0,0 +1,17 @@
#!/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 traffic_analysis.mov file from Google Drive
gdown -O "$DIR/data/traffic_analysis.mov" "https://drive.google.com/uc?id=1qadBd7lgpediafCpL_yedGjQPk-FLK-W"
# Download the traffic_analysis.pt file from Google Drive
gdown -O "$DIR/data/traffic_analysis.pt" "https://drive.google.com/uc?id=1y-IfToCjRXa3ZdC1JpnKRopC7mcQW-5z"
+17 -13
View File
@@ -1,5 +1,5 @@
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
repo_name: roboflow/supervision
@@ -26,25 +26,29 @@ extra_css:
nav:
- Home: index.md
- Quickstart:
- Detections: quickstart/detections.md
- API reference:
- How to:
- Detect and Annotate: how_to/detect_and_annotate.md
- Process Video: how_to/process_video.md
- Track Objects: how_to/track_objects.md
- Filter Detections: how_to/filter_detections.md
- Evaluate Model: how_to/evaluate_model.md
- API:
- 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
- Trackers:
- Core: tracker/core.md
- Dataset:
- Core: dataset/core.md
- Tools:
- Line Zone: detection/tools/line_zone.md
- Polygon Zone: detection/tools/polygon_zone.md
- Inference Slicer: detection/tools/inference_slicer.md
- Annotators: annotators.md
- Trackers: trackers.md
- Datasets: datasets.md
- Metrics:
- Detection Models: metrics/detection.md
- Object Detection: metrics/detection.md
- Draw:
- Color: draw/color.md
- Utils: draw/utils.md
- Utils:
- Video: utils/video.md
Generated
+98 -96
View File
@@ -493,6 +493,7 @@ files = [
{file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"},
{file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"},
{file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"},
{file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"},
{file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"},
{file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"},
{file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"},
@@ -501,6 +502,7 @@ files = [
{file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"},
{file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"},
{file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"},
{file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"},
{file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"},
{file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"},
{file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"},
@@ -509,6 +511,7 @@ files = [
{file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"},
{file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"},
{file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"},
{file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"},
{file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"},
{file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"},
{file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"},
@@ -517,6 +520,7 @@ files = [
{file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"},
{file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"},
{file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"},
{file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"},
{file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"},
{file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"},
{file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"},
@@ -539,34 +543,34 @@ test-no-images = ["pytest", "pytest-cov", "wurlitzer"]
[[package]]
name = "cryptography"
version = "41.0.2"
version = "41.0.4"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
files = [
{file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711"},
{file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7"},
{file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d"},
{file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f"},
{file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182"},
{file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83"},
{file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5"},
{file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58"},
{file = "cryptography-41.0.2-cp37-abi3-win32.whl", hash = "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76"},
{file = "cryptography-41.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4"},
{file = "cryptography-41.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a"},
{file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd"},
{file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766"},
{file = "cryptography-41.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee"},
{file = "cryptography-41.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831"},
{file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b"},
{file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa"},
{file = "cryptography-41.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e"},
{file = "cryptography-41.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14"},
{file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2"},
{file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f"},
{file = "cryptography-41.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0"},
{file = "cryptography-41.0.2.tar.gz", hash = "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c"},
{file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839"},
{file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f"},
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714"},
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb"},
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13"},
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143"},
{file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397"},
{file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860"},
{file = "cryptography-41.0.4-cp37-abi3-win32.whl", hash = "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd"},
{file = "cryptography-41.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d"},
{file = "cryptography-41.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67"},
{file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e"},
{file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829"},
{file = "cryptography-41.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca"},
{file = "cryptography-41.0.4-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d"},
{file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac"},
{file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9"},
{file = "cryptography-41.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"},
{file = "cryptography-41.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91"},
{file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8"},
{file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6"},
{file = "cryptography-41.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311"},
{file = "cryptography-41.0.4.tar.gz", hash = "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a"},
]
[package.dependencies]
@@ -1451,6 +1455,16 @@ files = [
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
{file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
{file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@@ -2154,77 +2168,65 @@ files = [
[[package]]
name = "pillow"
version = "9.5.0"
version = "10.0.1"
description = "Python Imaging Library (Fork)"
optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
files = [
{file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"},
{file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"},
{file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"},
{file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"},
{file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"},
{file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"},
{file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"},
{file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"},
{file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"},
{file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"},
{file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"},
{file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"},
{file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"},
{file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"},
{file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"},
{file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"},
{file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"},
{file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"},
{file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"},
{file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"},
{file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"},
{file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"},
{file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"},
{file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"},
{file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"},
{file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"},
{file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"},
{file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"},
{file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"},
{file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"},
{file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"},
{file = "Pillow-10.0.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:8f06be50669087250f319b706decf69ca71fdecd829091a37cc89398ca4dc17a"},
{file = "Pillow-10.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50bd5f1ebafe9362ad622072a1d2f5850ecfa44303531ff14353a4059113b12d"},
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6a90167bcca1216606223a05e2cf991bb25b14695c518bc65639463d7db722d"},
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f11c9102c56ffb9ca87134bd025a43d2aba3f1155f508eff88f694b33a9c6d19"},
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:186f7e04248103482ea6354af6d5bcedb62941ee08f7f788a1c7707bc720c66f"},
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0462b1496505a3462d0f35dc1c4d7b54069747d65d00ef48e736acda2c8cbdff"},
{file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d889b53ae2f030f756e61a7bff13684dcd77e9af8b10c6048fb2c559d6ed6eaf"},
{file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:552912dbca585b74d75279a7570dd29fa43b6d93594abb494ebb31ac19ace6bd"},
{file = "Pillow-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:787bb0169d2385a798888e1122c980c6eff26bf941a8ea79747d35d8f9210ca0"},
{file = "Pillow-10.0.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fd2a5403a75b54661182b75ec6132437a181209b901446ee5724b589af8edef1"},
{file = "Pillow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d7e91b4379f7a76b31c2dda84ab9e20c6220488e50f7822e59dac36b0cd92b1"},
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e9adb3f22d4c416e7cd79b01375b17159d6990003633ff1d8377e21b7f1b21"},
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93139acd8109edcdeffd85e3af8ae7d88b258b3a1e13a038f542b79b6d255c54"},
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:92a23b0431941a33242b1f0ce6c88a952e09feeea9af4e8be48236a68ffe2205"},
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cbe68deb8580462ca0d9eb56a81912f59eb4542e1ef8f987405e35a0179f4ea2"},
{file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:522ff4ac3aaf839242c6f4e5b406634bfea002469656ae8358644fc6c4856a3b"},
{file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:84efb46e8d881bb06b35d1d541aa87f574b58e87f781cbba8d200daa835b42e1"},
{file = "Pillow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:898f1d306298ff40dc1b9ca24824f0488f6f039bc0e25cfb549d3195ffa17088"},
{file = "Pillow-10.0.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:bcf1207e2f2385a576832af02702de104be71301c2696d0012b1b93fe34aaa5b"},
{file = "Pillow-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d6c9049c6274c1bb565021367431ad04481ebb54872edecfcd6088d27edd6ed"},
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28444cb6ad49726127d6b340217f0627abc8732f1194fd5352dec5e6a0105635"},
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de596695a75496deb3b499c8c4f8e60376e0516e1a774e7bc046f0f48cd620ad"},
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2872f2d7846cf39b3dbff64bc1104cc48c76145854256451d33c5faa55c04d1a"},
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ce90f8a24e1c15465048959f1e94309dfef93af272633e8f37361b824532e91"},
{file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ee7810cf7c83fa227ba9125de6084e5e8b08c59038a7b2c9045ef4dde61663b4"},
{file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1be1c872b9b5fcc229adeadbeb51422a9633abd847c0ff87dc4ef9bb184ae08"},
{file = "Pillow-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:98533fd7fa764e5f85eebe56c8e4094db912ccbe6fbf3a58778d543cadd0db08"},
{file = "Pillow-10.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:764d2c0daf9c4d40ad12fbc0abd5da3af7f8aa11daf87e4fa1b834000f4b6b0a"},
{file = "Pillow-10.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fcb59711009b0168d6ee0bd8fb5eb259c4ab1717b2f538bbf36bacf207ef7a68"},
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:697a06bdcedd473b35e50a7e7506b1d8ceb832dc238a336bd6f4f5aa91a4b500"},
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f665d1e6474af9f9da5e86c2a3a2d2d6204e04d5af9c06b9d42afa6ebde3f21"},
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:2fa6dd2661838c66f1a5473f3b49ab610c98a128fc08afbe81b91a1f0bf8c51d"},
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:3a04359f308ebee571a3127fdb1bd01f88ba6f6fb6d087f8dd2e0d9bff43f2a7"},
{file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:723bd25051454cea9990203405fa6b74e043ea76d4968166dfd2569b0210886a"},
{file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:71671503e3015da1b50bd18951e2f9daf5b6ffe36d16f1eb2c45711a301521a7"},
{file = "Pillow-10.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:44e7e4587392953e5e251190a964675f61e4dae88d1e6edbe9f36d6243547ff3"},
{file = "Pillow-10.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:3855447d98cced8670aaa63683808df905e956f00348732448b5a6df67ee5849"},
{file = "Pillow-10.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed2d9c0704f2dc4fa980b99d565c0c9a543fe5101c25b3d60488b8ba80f0cce1"},
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5bb289bb835f9fe1a1e9300d011eef4d69661bb9b34d5e196e5e82c4cb09b37"},
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0d3e54ab1df9df51b914b2233cf779a5a10dfd1ce339d0421748232cea9876"},
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2cc6b86ece42a11f16f55fe8903595eff2b25e0358dec635d0a701ac9586588f"},
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ca26ba5767888c84bf5a0c1a32f069e8204ce8c21d00a49c90dabeba00ce0145"},
{file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f0b4b06da13275bc02adfeb82643c4a6385bd08d26f03068c2796f60d125f6f2"},
{file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bc2e3069569ea9dbe88d6b8ea38f439a6aad8f6e7a6283a38edf61ddefb3a9bf"},
{file = "Pillow-10.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8b451d6ead6e3500b6ce5c7916a43d8d8d25ad74b9102a629baccc0808c54971"},
{file = "Pillow-10.0.1-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:32bec7423cdf25c9038fef614a853c9d25c07590e1a870ed471f47fb80b244db"},
{file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cf63d2c6928b51d35dfdbda6f2c1fddbe51a6bc4a9d4ee6ea0e11670dd981e"},
{file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f6d3d4c905e26354e8f9d82548475c46d8e0889538cb0657aa9c6f0872a37aa4"},
{file = "Pillow-10.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:847e8d1017c741c735d3cd1883fa7b03ded4f825a6e5fcb9378fd813edee995f"},
{file = "Pillow-10.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7f771e7219ff04b79e231d099c0a28ed83aa82af91fd5fa9fdb28f5b8d5addaf"},
{file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459307cacdd4138edee3875bbe22a2492519e060660eaf378ba3b405d1c66317"},
{file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b059ac2c4c7a97daafa7dc850b43b2d3667def858a4f112d1aa082e5c3d6cf7d"},
{file = "Pillow-10.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6caf3cd38449ec3cd8a68b375e0c6fe4b6fd04edb6c9766b55ef84a6e8ddf2d"},
{file = "Pillow-10.0.1.tar.gz", hash = "sha256:d72967b06be9300fed5cfbc8b5bafceec48bf7cdc7dab66b1d2549035287191d"},
]
[package.extras]
@@ -3356,13 +3358,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake
[[package]]
name = "urllib3"
version = "2.0.4"
version = "2.0.7"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.7"
files = [
{file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"},
{file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"},
{file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"},
{file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"},
]
[package.extras]
@@ -3518,4 +3520,4 @@ desktop = ["opencv-python"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.8,<3.12.0"
content-hash = "fcefb11e72c40fa7defc13f4a9cb1fe24b9d3d171b64bb54fc263d8add9ef40f"
content-hash = "beb692d89611ce85f8b2992f4e6da71fd14fa2ca75742ddae1a1c7b77df134f7"
+6 -5
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "supervision"
version = "0.14.0"
version = "0.16.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>"]
@@ -13,7 +13,9 @@ documentation = "https://github.com/roboflow/supervision/blob/main/README.md"
keywords = ["machine-learning", "deep-learning", "vision", "ML", "DL", "AI", "YOLOv5", "YOLOv8", "Roboflow"]
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Education',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
@@ -28,8 +30,7 @@ classifiers=[
"Topic :: Scientific/Engineering :: Image Recognition",
'Typing :: Typed',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Operating System :: Unix',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS'
]
@@ -38,7 +39,7 @@ python = ">=3.8,<3.12.0"
numpy = "^1.20.0"
matplotlib = "^3.7.1"
pyyaml = "^6.0"
pillow = "^9.4.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"
@@ -175,7 +176,7 @@ max-args = 20
include-package-data = false
[tool.setuptools.packages.find]
exclude = ["docs*", "test*"]
exclude = ["docs*", "test*","examples*"]
[build-system]
requires = ["poetry-core"]
+25 -3
View File
@@ -6,14 +6,28 @@ try:
except importlib_metadata.PackageNotFoundError:
__version__ = "development"
from supervision.annotators.core import (
BlurAnnotator,
BoundingBoxAnnotator,
BoxCornerAnnotator,
BoxMaskAnnotator,
CircleAnnotator,
DotAnnotator,
EllipseAnnotator,
HaloAnnotator,
HeatMapAnnotator,
LabelAnnotator,
MaskAnnotator,
TraceAnnotator,
)
from supervision.annotators.utils import ColorLookup
from supervision.classification.core import Classifications
from supervision.dataset.core import (
BaseDataset,
ClassificationDataset,
DetectionDataset,
)
from supervision.detection.annotate import BoxAnnotator, MaskAnnotator
from supervision.detection.annotate import BoxAnnotator
from supervision.detection.core import Detections
from supervision.detection.line_counter import LineZone, LineZoneAnnotator
from supervision.detection.tools.inference_slicer import InferenceSlicer
@@ -28,7 +42,14 @@ from supervision.detection.utils import (
polygon_to_xyxy,
)
from supervision.draw.color import Color, ColorPalette
from supervision.draw.utils import draw_filled_rectangle, draw_polygon, draw_text
from supervision.draw.utils import (
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
@@ -37,6 +58,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,
View File
+11
View File
@@ -0,0 +1,11 @@
from abc import ABC, abstractmethod
import numpy as np
from supervision.detection.core import Detections
class BaseAnnotator(ABC):
@abstractmethod
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
pass
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
from enum import Enum
from typing import Optional, Union
import numpy as np
from supervision.detection.core import Detections
from supervision.draw.color import Color, ColorPalette
from supervision.geometry.core import Position
class ColorLookup(Enum):
"""
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_lookup: Union[ColorLookup, np.ndarray] = ColorLookup.CLASS,
) -> int:
if detection_idx >= len(detections):
raise ValueError(
f"Detection index {detection_idx}"
f"is out of bounds for detections of length {len(detections)}"
)
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_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_lookup == ColorLookup.TRACK:
if detections.tracker_id is None:
raise ValueError(
"Could not resolve color by track because"
"Detections do not have tracker_id"
)
return detections.tracker_id[detection_idx]
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,
max_size: Optional[int] = None,
start_frame_id: int = 0,
anchor: Position = Position.CENTER,
) -> None:
self.current_frame_id = start_frame_id
self.max_size = max_size
self.anchor = anchor
self.frame_id = np.array([], dtype=int)
self.xy = np.empty((0, 2), dtype=np.float32)
self.tracker_id = np.array([], dtype=int)
def put(self, detections: Detections) -> None:
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.tracker_id = np.concatenate([self.tracker_id, detections.tracker_id])
unique_frame_id = np.unique(self.frame_id)
if 0 < self.max_size < len(unique_frame_id):
max_allowed_frame_id = self.current_frame_id - self.max_size + 1
filtering_mask = self.frame_id >= max_allowed_frame_id
self.frame_id = self.frame_id[filtering_mask]
self.xy = self.xy[filtering_mask]
self.tracker_id = self.tracker_id[filtering_mask]
self.current_frame_id += 1
def get(self, tracker_id: int) -> np.ndarray:
return self.xy[self.tracker_id == tracker_id]
+1 -38
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,41 +39,6 @@ class Classifications:
_validate_class_ids(self.class_id, n)
_validate_confidence(self.confidence, n)
@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:
"""
Creates a Classifications 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:
Classifications: A new Classifications object.
Example:
```python
>>> import cv2
>>> from ultralytics import YOLO
>>> 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)
```
"""
confidence = yolov8_results.probs.data.cpu().numpy()
return cls(class_id=np.arange(confidence.shape[0]), confidence=confidence)
@classmethod
def from_ultralytics(cls, ultralytics_results) -> Classifications:
"""
@@ -84,7 +47,7 @@ class Classifications:
Args:
ultralytics_results (ultralytics.engine.results.Results):
The output Results instance from ultralytics model
The output Results instance from ultralytics model
Returns:
Classifications: A new Classifications object.
+4 -6
View File
@@ -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(
@@ -563,8 +562,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:
-58
View File
@@ -144,61 +144,3 @@ class BoxAnnotator:
lineType=cv2.LINE_AA,
)
return scene
class MaskAnnotator:
"""
A class for overlaying masks on an image using detections provided.
Attributes:
color (Union[Color, ColorPalette]): The color to fill the mask,
can be a single color or a color palette
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
):
self.color: Union[Color, ColorPalette] = color
def annotate(
self, scene: np.ndarray, detections: Detections, opacity: float = 0.5
) -> np.ndarray:
"""
Overlays the masks on the given image based on the provided detections,
with a specified opacity.
Args:
scene (np.ndarray): The image on which the masks will be overlaid
detections (Detections): The detections for which the
masks will be overlaid
opacity (float): The opacity of the masks, between 0 and 1, default is 0.5
Returns:
np.ndarray: The image with the masks overlaid
"""
if detections.mask is None:
return scene
for i in np.flip(np.argsort(detections.area)):
class_id = (
detections.class_id[i] if detections.class_id is not None else None
)
idx = class_id if class_id is not None else i
color = (
self.color.by_idx(idx)
if isinstance(self.color, ColorPalette)
else self.color
)
mask = detections.mask[i]
colored_mask = np.zeros_like(scene, dtype=np.uint8)
colored_mask[:] = color.as_bgr()
scene = np.where(
np.expand_dims(mask, axis=-1),
np.uint8(opacity * colored_mask + (1 - opacity) * scene),
scene,
)
return scene
+73 -58
View File
@@ -12,7 +12,6 @@ from supervision.detection.utils import (
xywh_to_xyxy,
)
from supervision.geometry.core import Position
from supervision.utils.internal import deprecated
def _validate_xyxy(xyxy: Any, n: int) -> None:
@@ -78,7 +77,7 @@ class Detections:
"""
xyxy: np.ndarray
mask: np.Optional[np.ndarray] = None
mask: Optional[np.ndarray] = None
confidence: Optional[np.ndarray] = None
class_id: Optional[np.ndarray] = None
tracker_id: Optional[np.ndarray] = None
@@ -178,51 +177,13 @@ class Detections:
```
"""
yolov5_detections_predictions = yolov5_results.pred[0].cpu().cpu().numpy()
return cls(
xyxy=yolov5_detections_predictions[:, :4],
confidence=yolov5_detections_predictions[:, 4],
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:
"""
@@ -255,6 +216,7 @@ class Detections:
>>> detections = sv.Detections.from_ultralytics(result)
```
"""
return cls(
xyxy=ultralytics_results.boxes.xyxy.cpu().numpy(),
confidence=ultralytics_results.boxes.conf.cpu().numpy(),
@@ -293,6 +255,9 @@ class Detections:
>>> detections = sv.Detections.from_yolo_nas(result)
```
"""
if np.asarray(yolo_nas_results.prediction.bboxes_xyxy).shape[0] == 0:
return cls.empty()
return cls(
xyxy=yolo_nas_results.prediction.bboxes_xyxy,
confidence=yolo_nas_results.prediction.confidence,
@@ -320,14 +285,16 @@ class Detections:
>>> yolo_pipeline = Pipeline.create(
... task="yolo",
... model_stub = "zoo:cv/detection/yolov5-l/pytorch/" \
... 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)
>>> result = list(pipeline_outputs.boxes[0])
>>> detections = sv.Detections.from_yolo_nas(result)
>>> detections = sv.Detections.from_deepsparse(result)
```
"""
if np.asarray(deepsparse_results.boxes[0]).shape[0] == 0:
return cls.empty()
return cls(
xyxy=np.array(deepsparse_results.boxes[0]),
confidence=np.array(deepsparse_results.scores[0]),
@@ -360,6 +327,7 @@ class Detections:
>>> detections = sv.Detections.from_mmdet(mmdet_result)
```
"""
return cls(
xyxy=mmdet_results.pred_instances.bboxes.cpu().numpy(),
confidence=mmdet_results.pred_instances.scores.cpu().numpy(),
@@ -375,6 +343,7 @@ class Detections:
Returns:
Detections: A new Detections object.
"""
return cls(
xyxy=transformers_results["boxes"].cpu().numpy(),
confidence=transformers_results["scores"].cpu().numpy(),
@@ -411,6 +380,7 @@ class Detections:
>>> detections = sv.Detections.from_detectron2(result)
```
"""
return cls(
xyxy=detectron2_results["instances"].pred_boxes.tensor.cpu().numpy(),
confidence=detectron2_results["instances"].scores.cpu().numpy(),
@@ -421,7 +391,7 @@ class Detections:
)
@classmethod
def from_roboflow(cls, roboflow_result: dict, class_list: List[str]) -> Detections:
def from_roboflow(cls, roboflow_result: dict) -> Detections:
"""
Create a Detections object from the [Roboflow](https://roboflow.com/)
API inference result.
@@ -429,8 +399,6 @@ class Detections:
Args:
roboflow_result (dict): The result from the
Roboflow API containing predictions.
class_list (List[str]): A list of class names
corresponding to the class IDs in the API result.
Returns:
(Detections): A Detections object containing the bounding boxes, class IDs,
@@ -447,25 +415,30 @@ class Detections:
... "y": 0.5,
... "width": 0.2,
... "height": 0.3,
... "class_id": 0,
... "class": "person",
... "confidence": 0.9
... },
... # ... more predictions ...
... ]
... }
>>> class_list = ["person", "car", "dog"]
>>> detections = sv.Detections.from_roboflow(roboflow_result, class_list)
>>> detections = sv.Detections.from_roboflow(roboflow_result)
```
"""
xyxy, confidence, class_id, masks = process_roboflow_result(
roboflow_result=roboflow_result, class_list=class_list
xyxy, confidence, class_id, masks, trackers = process_roboflow_result(
roboflow_result=roboflow_result
)
return Detections(
if np.asarray(xyxy).shape[0] == 0:
return cls.empty()
return cls(
xyxy=xyxy,
confidence=confidence,
class_id=class_id,
mask=masks,
tracker_id=trackers,
)
@classmethod
@@ -504,7 +477,11 @@ class Detections:
xywh = np.array([mask["bbox"] for mask in sorted_generated_masks])
mask = np.array([mask["segmentation"] for mask in sorted_generated_masks])
return Detections(xyxy=xywh_to_xyxy(boxes_xywh=xywh), mask=mask)
if np.asarray(xywh).shape[0] == 0:
return cls.empty()
xyxy = xywh_to_xyxy(boxes_xywh=xywh)
return cls(xyxy=xyxy, mask=mask)
@classmethod
def from_paddledet(cls, paddledet_result) -> Detections:
@@ -538,6 +515,10 @@ class Detections:
>>> detections = sv.Detections.from_paddledet(paddledet_result)
```
"""
if np.asarray(paddledet_result["bbox"][:, 2:6]).shape[0] == 0:
return cls.empty()
return cls(
xyxy=paddledet_result["bbox"][:, 2:6],
confidence=paddledet_result["bbox"][:, 1],
@@ -621,15 +602,23 @@ class Detections:
def get_anchor_coordinates(self, anchor: Position) -> np.ndarray:
"""
Returns the bounding box coordinates for a specific anchor.
Calculates and returns the coordinates of a specific anchor point
within the bounding boxes defined by the `xyxy` attribute. The anchor
point can be any of the predefined positions in the `Position` enum,
such as `CENTER`, `CENTER_LEFT`, `BOTTOM_RIGHT`, etc.
Args:
anchor (Position): Position of bounding box anchor
for which to return the coordinates.
anchor (Position): An enum specifying the position of the anchor point
within the bounding box. Supported positions are defined in the
`Position` enum.
Returns:
np.ndarray: An array of shape `(n, 2)` containing the bounding
box anchor coordinates in format `[x, y]`.
np.ndarray: An array of shape `(n, 2)`, where `n` is the number of bounding
boxes. Each row contains the `[x, y]` coordinates of the specified
anchor point for the corresponding bounding box.
Raises:
ValueError: If the provided `anchor` is not supported.
"""
if anchor == Position.CENTER:
return np.array(
@@ -638,10 +627,36 @@ class Detections:
(self.xyxy[:, 1] + self.xyxy[:, 3]) / 2,
]
).transpose()
elif anchor == Position.CENTER_LEFT:
return np.array(
[
self.xyxy[:, 0],
(self.xyxy[:, 1] + self.xyxy[:, 3]) / 2,
]
).transpose()
elif anchor == Position.CENTER_RIGHT:
return np.array(
[
self.xyxy[:, 2],
(self.xyxy[:, 1] + self.xyxy[:, 3]) / 2,
]
).transpose()
elif anchor == Position.BOTTOM_CENTER:
return np.array(
[(self.xyxy[:, 0] + self.xyxy[:, 2]) / 2, self.xyxy[:, 3]]
).transpose()
elif anchor == Position.BOTTOM_LEFT:
return np.array([self.xyxy[:, 0], self.xyxy[:, 3]]).transpose()
elif anchor == Position.BOTTOM_RIGHT:
return np.array([self.xyxy[:, 2], self.xyxy[:, 3]]).transpose()
elif anchor == Position.TOP_CENTER:
return np.array(
[(self.xyxy[:, 0] + self.xyxy[:, 2]) / 2, self.xyxy[:, 1]]
).transpose()
elif anchor == Position.TOP_LEFT:
return np.array([self.xyxy[:, 0], self.xyxy[:, 1]]).transpose()
elif anchor == Position.TOP_RIGHT:
return np.array([self.xyxy[:, 2], self.xyxy[:, 1]]).transpose()
raise ValueError(f"{anchor} is not supported.")
+35 -16
View File
@@ -1,4 +1,4 @@
from typing import Dict, Optional
from typing import Dict, Optional, Tuple
import cv2
import numpy as np
@@ -10,37 +10,54 @@ from supervision.geometry.core import Point, 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 utilizes 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):
"""
Initialize a LineCounter object.
Attributes:
Args:
start (Point): The starting point of the line.
end (Point): The ending point of the line.
"""
self.vector = Vector(start=start, end=end)
self.tracker_state: Dict[str, bool] = {}
self.in_count: int = 0
self.out_count: int = 0
def trigger(self, detections: Detections):
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)
for i, (xyxy, _, confidence, class_id, tracker_id) in enumerate(detections):
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),
@@ -50,25 +67,27 @@ class LineZone:
]
triggers = [self.vector.is_in(point=anchor) for anchor in 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:
+38 -13
View File
@@ -1,3 +1,4 @@
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Callable, Optional, Tuple
import numpy as np
@@ -23,19 +24,21 @@ def move_detections(detections: Detections, offset: np.array) -> Detections:
class InferenceSlicer:
"""
InferenceSlicer performs slicing-based inference for small target detection. This
method, often referred to as Slicing Adaptive Inference (SAHI), involves dividing a
larger image into smaller slices, performing inference on each slice, and then
merging the detections.
method, often referred to as
[Slicing Adaptive Inference (SAHI)](https://ieeexplore.ieee.org/document/9897990),
involves dividing a larger image into smaller slices, performing inference on each
slice, and then merging the detections.
Attributes:
Args:
slice_wh (Tuple[int, int]): Dimensions of each slice in the format
`(width, height)`.
overlap_ratio_wh (Tuple[float, float]): Overlap ratio between consecutive
slices in the format `(width_ratio, height_ratio)`.
iou_threshold (Optional[float]): Intersection over Union (IoU) threshold used
for non-max suppression.
callback (Callable): A function that performs inference on a given image slice
and returns detections.
iou_threshold (Optional[float]): Intersection over Union (IoU) threshold
used for non-max suppression.
callback (Callable): A function that performs inference on a given image
slice and returns detections.
thread_workers (int): Number of threads for parallel execution.
Note:
The class ensures that slices do not exceed the boundaries of the original
@@ -50,11 +53,13 @@ class InferenceSlicer:
slice_wh: Tuple[int, int] = (320, 320),
overlap_ratio_wh: Tuple[float, float] = (0.2, 0.2),
iou_threshold: Optional[float] = 0.5,
thread_workers: int = 1,
):
self.slice_wh = slice_wh
self.overlap_ratio_wh = overlap_ratio_wh
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:
@@ -97,15 +102,35 @@ class InferenceSlicer:
overlap_ratio_wh=self.overlap_ratio_wh,
)
for offset in offsets:
image_slice = crop_image(image=image, xyxy=offset)
detections = self.callback(image_slice)
detections = move_detections(detections=detections, offset=offset[:2])
detections_list.append(detections)
with ThreadPoolExecutor(max_workers=self.thread_workers) as executor:
futures = [
executor.submit(self._run_callback, image, offset) for offset in offsets
]
for future in as_completed(futures):
detections_list.append(future.result())
return Detections.merge(detections_list=detections_list).with_nms(
threshold=self.iou_threshold
)
def _run_callback(self, image, offset) -> Detections:
"""
Run the provided callback on a slice of an image.
Args:
image (np.ndarray): The input image on which inference needs to run
offset (np.ndarray): An array of shape `(4,)` containing coordinates
for the slice.
Returns:
Detections: A collection of detections for the slice.
"""
image_slice = crop_image(image=image, xyxy=offset)
detections = self.callback(image_slice)
detections = move_detections(detections=detections, offset=offset[:2])
return detections
@staticmethod
def _generate_offset(
resolution_wh: Tuple[int, int],
+1 -1
View File
@@ -63,7 +63,7 @@ class PolygonZone:
clipped_detections.get_anchor_coordinates(anchor=self.triggering_position)
).astype(int)
is_in_zone = self.mask[clipped_anchors[:, 1], clipped_anchors[:, 0]]
self.current_count = np.sum(is_in_zone)
self.current_count = int(np.sum(is_in_zone))
return is_in_zone.astype(bool)
+12 -6
View File
@@ -332,15 +332,16 @@ def extract_ultralytics_masks(yolov8_results) -> Optional[np.ndarray]:
def process_roboflow_result(
roboflow_result: dict, class_list: List[str]
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray]]:
roboflow_result: dict,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray], 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
xyxy = []
confidence = []
class_id = []
masks = []
tracker_ids = []
image_width = int(roboflow_result["image"]["width"])
image_height = int(roboflow_result["image"]["height"])
@@ -357,24 +358,29 @@ def process_roboflow_result(
if "points" not in prediction:
xyxy.append([x_min, y_min, x_max, y_max])
class_id.append(class_list.index(prediction["class"]))
class_id.append(prediction["class_id"])
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
)
mask = polygon_to_mask(polygon, resolution_wh=(image_width, image_height))
xyxy.append([x_min, y_min, x_max, y_max])
class_id.append(class_list.index(prediction["class"]))
class_id.append(prediction["class_id"])
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)
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
return xyxy, confidence, class_id, masks
return xyxy, confidence, class_id, masks, tracker_id
def move_boxes(xyxy: np.ndarray, offset: np.ndarray) -> np.ndarray:
+72 -21
View File
@@ -4,6 +4,7 @@ from dataclasses import dataclass
from typing import List, Tuple
DEFAULT_COLOR_PALETTE = [
"#a351fb",
"#e6194b",
"#3cb44b",
"#ffe119",
@@ -33,21 +34,35 @@ def _validate_color_hex(color_hex: str):
@dataclass
class Color:
"""
Represents a color in RGB format.
Attributes:
r (int): Red channel.
g (int): Green channel.
b (int): Blue channel.
"""
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')
```
>>> Color.from_hex('#ff00ff')
Color(r=255, g=0, b=255)
```
"""
_validate_color_hex(color_hex)
color_hex = color_hex.lstrip("#")
@@ -58,17 +73,31 @@ class Color:
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:
```
>>> color.as_rgb()
(255, 0, 255)
```
"""
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:
```
>>> color.as_bgr()
(255, 0, 255)
```
"""
return self.b, self.g, self.r
@@ -99,33 +128,55 @@ class ColorPalette:
@classmethod
def default(cls) -> ColorPalette:
"""
Returns a default color palette.
Returns:
ColorPalette: A ColorPalette instance with default colors.
Example:
```
>>> ColorPalette.default()
ColorPalette(colors=[Color(r=255, g=0, b=0), Color(r=0, g=255, b=0), ...])
```
"""
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'])
```
>>> 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:
"""
Returns the color at a given index in the color palette.
Return the color at a given index in the palette.
:param idx: int : The index of the color in the color palette
:return: Color : The color at the given index
Args:
idx (int): Index of the color in the palette.
Returns:
Color: Color at the given index.
Example:
color_palette = ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
color = color_palette.by_idx(1)
```
>>> color_palette.by_idx(1)
Color(r=0, g=255, b=0)
```
"""
if idx < 0:
raise ValueError("idx argument should not be negative")
+64 -1
View File
@@ -1,4 +1,5 @@
from typing import Optional
import os
from typing import Optional, Union
import cv2
import numpy as np
@@ -168,3 +169,65 @@ 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
+11
View File
@@ -6,8 +6,19 @@ from typing import Tuple
class Position(Enum):
"""
Enum representing the position of an anchor point.
"""
CENTER = "CENTER"
CENTER_LEFT = "CENTER_LEFT"
CENTER_RIGHT = "CENTER_RIGHT"
TOP_CENTER = "TOP_CENTER"
TOP_LEFT = "TOP_LEFT"
TOP_RIGHT = "TOP_RIGHT"
BOTTOM_LEFT = "BOTTOM_LEFT"
BOTTOM_CENTER = "BOTTOM_CENTER"
BOTTOM_RIGHT = "BOTTOM_RIGHT"
@classmethod
def list(cls):
+2
View File
@@ -249,6 +249,8 @@ class ByteTrack:
detections.confidence = np.array(
[t.score for t in tracks], dtype=np.float32
)
else:
detections.tracker_id = np.array([], dtype=int)
return detections
+66 -7
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
import time
from collections import deque
from dataclasses import dataclass
from typing import Callable, Generator, Optional, Tuple
@@ -65,28 +67,33 @@ class VideoSink:
target_path (str): The path to the output file where the video will be saved.
video_info (VideoInfo): Information about the video resolution, fps,
and total frame count.
codec (str): FOURCC code for video format
Example:
```python
>>> import supervision as sv
>>> video_info = sv.VideoInfo.from_video_path(video_path='source_video.mp4')
>>> video_info = sv.VideoInfo.from_video_path('source.mp4')
>>> frames_generator = get_video_frames_generator('source.mp4')
>>> with sv.VideoSink(target_path='target_video.mp4',
... video_info=video_info) as sink:
... for frame in get_video_frames_generator(source_path='source_video.mp4',
... stride=2):
>>> with sv.VideoSink(target_path='target.mp4', video_info=video_info) as sink:
... for frame in frames_generator:
... sink.write_frame(frame=frame)
```
"""
def __init__(self, target_path: str, video_info: VideoInfo):
def __init__(self, target_path: str, video_info: VideoInfo, codec: str = "mp4v"):
self.target_path = target_path
self.video_info = video_info
self.__fourcc = cv2.VideoWriter_fourcc(*"mp4v")
self.__codec = codec
self.__writer = None
def __enter__(self):
try:
self.__fourcc = cv2.VideoWriter_fourcc(*self.__codec)
except TypeError as e:
print(str(e) + ". Defaulting to mp4v...")
self.__fourcc = cv2.VideoWriter_fourcc(*"mp4v")
self.__writer = cv2.VideoWriter(
self.target_path,
self.__fourcc,
@@ -195,3 +202,55 @@ def process_video(
):
result_frame = callback(frame, index)
sink.write_frame(frame=result_frame)
class FPSMonitor:
"""
A class for monitoring frames per second (FPS) to benchmark latency.
"""
def __init__(self, sample_size: int = 30):
"""
Args:
sample_size (int): The maximum number of observations for latency
benchmarking.
Examples:
```python
>>> import supervision as sv
>>> frames_generator = sv.get_video_frames_generator('source.mp4')
>>> fps_monitor = sv.FPSMonitor()
>>> for frame in frames_generator:
... # your processing code here
... fps_monitor.tick()
... fps = fps_monitor()
```
"""
self.all_timestamps = deque(maxlen=sample_size)
def __call__(self) -> float:
"""
Computes and returns the average FPS based on the stored time stamps.
Returns:
float: The average FPS. Returns 0.0 if no time stamps are stored.
"""
if not self.all_timestamps:
return 0.0
taken_time = self.all_timestamps[-1] - self.all_timestamps[0]
return (len(self.all_timestamps)) / taken_time if taken_time != 0 else 0.0
def tick(self) -> None:
"""
Adds a new time stamp to the deque for FPS calculation.
"""
self.all_timestamps.append(time.monotonic())
def reset(self) -> None:
"""
Clears all the time stamps from the deque.
"""
self.all_timestamps.clear()
View File
+109
View File
@@ -0,0 +1,109 @@
from contextlib import ExitStack as DoesNotRaise
from test.utils import mock_detections
from typing import Optional
import numpy as np
import pytest
from supervision.annotators.utils import ColorLookup, resolve_color_idx
from supervision.detection.core import Detections
@pytest.mark.parametrize(
"detections, detection_idx, color_lookup, expected_result, exception",
[
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
class_id=[5, 3],
tracker_id=[2, 6],
),
0,
ColorLookup.INDEX,
0,
DoesNotRaise(),
), # multiple detections; index lookup
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
class_id=[5, 3],
tracker_id=[2, 6],
),
0,
ColorLookup.CLASS,
5,
DoesNotRaise(),
), # multiple detections; class lookup
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
class_id=[5, 3],
tracker_id=[2, 6],
),
0,
ColorLookup.TRACK,
2,
DoesNotRaise(),
), # multiple detections; track lookup
(
Detections.empty(),
0,
ColorLookup.INDEX,
None,
pytest.raises(ValueError),
), # no detections; index lookup; out of bounds
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
class_id=[5, 3],
tracker_id=[2, 6],
),
2,
ColorLookup.INDEX,
None,
pytest.raises(ValueError),
), # multiple detections; index lookup; out of bounds
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
0,
ColorLookup.CLASS,
None,
pytest.raises(ValueError),
), # multiple detections; class lookup; no class_id
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
0,
ColorLookup.TRACK,
None,
pytest.raises(ValueError),
), # multiple detections; class lookup; no track_id
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
0,
np.array([1, 0]),
1,
DoesNotRaise(),
), # multiple detections; custom lookup; correct length
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
0,
np.array([1]),
None,
pytest.raises(ValueError),
), # multiple detections; custom lookup; wrong length
],
)
def test_resolve_color_idx(
detections: Detections,
detection_idx: int,
color_lookup: ColorLookup,
expected_result: Optional[int],
exception: Exception,
) -> None:
with exception:
result = resolve_color_idx(
detections=detections,
detection_idx=detection_idx,
color_lookup=color_lookup,
)
assert result == expected_result
+84 -1
View File
@@ -5,7 +5,8 @@ from typing import List, Optional, Union
import numpy as np
import pytest
from supervision import Detections
from supervision.detection.core import Detections
from supervision.geometry.core import Position
PREDICTIONS = np.array(
[
@@ -190,3 +191,85 @@ def test_merge(
with exception:
result = Detections.merge(detections_list=detections_list)
assert result == expected_result
@pytest.mark.parametrize(
"detections, anchor, expected_result, exception",
[
(
Detections.empty(),
Position.CENTER,
np.empty((0, 2), dtype=np.float32),
DoesNotRaise(),
), # empty detections
(
mock_detections(xyxy=[[10, 10, 20, 20]]),
Position.CENTER,
np.array([[15, 15]], dtype=np.float32),
DoesNotRaise(),
), # single detection; center anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.CENTER,
np.array([[15, 15], [25, 25]], dtype=np.float32),
DoesNotRaise(),
), # two detections; center anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.CENTER_LEFT,
np.array([[10, 15], [20, 25]], dtype=np.float32),
DoesNotRaise(),
), # two detections; center left anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.CENTER_RIGHT,
np.array([[20, 15], [30, 25]], dtype=np.float32),
DoesNotRaise(),
), # two detections; center right anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.TOP_CENTER,
np.array([[15, 10], [25, 20]], dtype=np.float32),
DoesNotRaise(),
), # two detections; top center anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.TOP_LEFT,
np.array([[10, 10], [20, 20]], dtype=np.float32),
DoesNotRaise(),
), # two detections; top left anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.TOP_RIGHT,
np.array([[20, 10], [30, 20]], dtype=np.float32),
DoesNotRaise(),
), # two detections; top right anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.BOTTOM_CENTER,
np.array([[15, 20], [25, 30]], dtype=np.float32),
DoesNotRaise(),
), # two detections; bottom center anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.BOTTOM_LEFT,
np.array([[10, 20], [20, 30]], dtype=np.float32),
DoesNotRaise(),
), # two detections; bottom left anchor
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
Position.BOTTOM_RIGHT,
np.array([[20, 20], [30, 30]], dtype=np.float32),
DoesNotRaise(),
), # two detections; bottom right anchor
],
)
def test_get_anchor_coordinates(
detections: Detections,
anchor: Position,
expected_result: np.ndarray,
exception: Exception,
) -> None:
result = detections.get_anchor_coordinates(anchor)
with exception:
assert np.array_equal(result, expected_result)
+27 -17
View File
@@ -260,12 +260,11 @@ def test_filter_polygons_by_area(
@pytest.mark.parametrize(
"roboflow_result, class_list, expected_result, exception",
"roboflow_result, expected_result, exception",
[
(
{"predictions": [], "image": {"width": 1000, "height": 1000}},
["person", "car", "truck"],
(np.empty((0, 4)), np.empty(0), np.empty(0), None),
(np.empty((0, 4)), np.empty(0), np.empty(0), None, None),
DoesNotRaise(),
), # empty result
(
@@ -277,17 +276,18 @@ def test_filter_polygons_by_area(
"width": 50.0,
"height": 50.0,
"confidence": 0.9,
"class_id": 0,
"class": "person",
}
],
"image": {"width": 1000, "height": 1000},
},
["person", "car", "truck"],
(
np.array([[175.0, 275.0, 225.0, 325.0]]),
np.array([0.9]),
np.array([0]),
None,
None,
),
DoesNotRaise(),
), # single correct object detection result
@@ -300,7 +300,9 @@ def test_filter_polygons_by_area(
"width": 50.0,
"height": 50.0,
"confidence": 0.9,
"class_id": 0,
"class": "person",
"tracker_id": 1,
},
{
"x": 500.0,
@@ -308,17 +310,19 @@ def test_filter_polygons_by_area(
"width": 100.0,
"height": 100.0,
"confidence": 0.8,
"class_id": 7,
"class": "truck",
"tracker_id": 2,
},
],
"image": {"width": 1000, "height": 1000},
},
["person", "car", "truck"],
(
np.array([[175.0, 275.0, 225.0, 325.0], [450.0, 450.0, 550.0, 550.0]]),
np.array([0.9, 0.8]),
np.array([0, 2]),
np.array([0, 7]),
None,
np.array([1, 2]),
),
DoesNotRaise(),
), # two correct object detection result
@@ -331,14 +335,15 @@ def test_filter_polygons_by_area(
"width": 50.0,
"height": 50.0,
"confidence": 0.9,
"class_id": 0,
"class": "person",
"points": [],
"tracker_id": None,
}
],
"image": {"width": 1000, "height": 1000},
},
["person", "car", "truck"],
(np.empty((0, 4)), np.empty(0), np.empty(0), None),
(np.empty((0, 4)), np.empty(0), np.empty(0), None, None),
DoesNotRaise(),
), # single incorrect instance segmentation result with no points
(
@@ -350,14 +355,14 @@ def test_filter_polygons_by_area(
"width": 50.0,
"height": 50.0,
"confidence": 0.9,
"class_id": 0,
"class": "person",
"points": [{"x": 200.0, "y": 300.0}, {"x": 250.0, "y": 300.0}],
}
],
"image": {"width": 1000, "height": 1000},
},
["person", "car", "truck"],
(np.empty((0, 4)), np.empty(0), np.empty(0), None),
(np.empty((0, 4)), np.empty(0), np.empty(0), None, None),
DoesNotRaise(),
), # single incorrect instance segmentation result with no enough points
(
@@ -369,6 +374,7 @@ def test_filter_polygons_by_area(
"width": 50.0,
"height": 50.0,
"confidence": 0.9,
"class_id": 0,
"class": "person",
"points": [
{"x": 200.0, "y": 300.0},
@@ -380,12 +386,12 @@ def test_filter_polygons_by_area(
],
"image": {"width": 1000, "height": 1000},
},
["person", "car", "truck"],
(
np.array([[175.0, 275.0, 225.0, 325.0]]),
np.array([0.9]),
np.array([0]),
TEST_MASK,
None,
),
DoesNotRaise(),
), # single incorrect instance segmentation result with no enough points
@@ -398,6 +404,7 @@ def test_filter_polygons_by_area(
"width": 50.0,
"height": 50.0,
"confidence": 0.9,
"class_id": 0,
"class": "person",
"points": [
{"x": 200.0, "y": 300.0},
@@ -412,18 +419,19 @@ def test_filter_polygons_by_area(
"width": 100.0,
"height": 100.0,
"confidence": 0.8,
"class_id": 7,
"class": "truck",
"points": [],
},
],
"image": {"width": 1000, "height": 1000},
},
["person", "car", "truck"],
(
np.array([[175.0, 275.0, 225.0, 325.0]]),
np.array([0.9]),
np.array([0]),
TEST_MASK,
None,
),
DoesNotRaise(),
), # two instance segmentation results - one correct, one incorrect
@@ -431,20 +439,22 @@ def test_filter_polygons_by_area(
)
def test_process_roboflow_result(
roboflow_result: dict,
class_list: List[str],
expected_result: Tuple[np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray]],
expected_result: Tuple[
np.ndarray, np.ndarray, np.ndarray, Optional[np.ndarray], np.ndarray
],
exception: Exception,
) -> None:
with exception:
result = process_roboflow_result(
roboflow_result=roboflow_result, class_list=class_list
)
result = process_roboflow_result(roboflow_result=roboflow_result)
assert np.array_equal(result[0], expected_result[0])
assert np.array_equal(result[1], expected_result[1])
assert np.array_equal(result[2], expected_result[2])
assert (result[3] is None and expected_result[3] is None) or (
np.array_equal(result[3], expected_result[3])
)
assert (result[4] is None and expected_result[4] is None) or (
np.array_equal(result[4], expected_result[4])
)
@pytest.mark.parametrize(