Compare commits

...
222 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
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 227615b766 fix: 🐛 exclude examples folder from package
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-08-31 20:08:29 +03:00
Onuralp SEZER baff75332f docs: 📝 example guide visual rules and license rule added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-08-31 20:03:02 +03:00
Onuralp SEZER 434a695324 docs: 📝 example guidelines added
Signed-off-by: Onuralp SEZER <thunderbirdtr@gmail.com>
2023-08-31 19:54:08 +03:00
Hardik Dava 5d71ab2961 Make with black again 2023-08-11 14:18:25 +02:00
Hardik Dava 5c9e529743 Make with isort 2023-08-11 14:15:47 +02:00
Hardik Dava 3f7043e780 Make with Black 2023-08-11 14:13:17 +02:00
Hardik Dava c746a7f9e4 docs added 2023-08-11 14:08:52 +02:00
Hardik Dava 04629cd7f4 initial commit 2023-08-11 14:07:14 +02:00
44 changed files with 2524 additions and 1082 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 -3
View File
@@ -15,12 +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 -r .github/requirements-dev.txt
- name: 🧪 Test
run: "python -m pytest ./test"
+3 -7
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
@@ -74,7 +70,7 @@ repos:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.291
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
+12 -1
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! 🤝
@@ -305,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">
@@ -352,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).
-19
View File
@@ -1,19 +0,0 @@
## BoundingBoxAnnotator
:::supervision.annotators.core.BoundingBoxAnnotator
## MaskAnnotator
:::supervision.annotators.core.MaskAnnotator
## EllipseAnnotator
:::supervision.annotators.core.EllipseAnnotator
## BoxCornerAnnotator
:::supervision.annotators.core.BoxCornerAnnotator
## LabelAnnotator
:::supervision.annotators.core.LabelAnnotator
+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
+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.
+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
+60 -72
View File
@@ -2168,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]
@@ -3370,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]
@@ -3532,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.15.0rc2"
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"]
+18 -2
View File
@@ -7,19 +7,27 @@ 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, TraceAnnotator
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
@@ -34,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
@@ -43,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,
-47
View File
@@ -1,55 +1,8 @@
from abc import ABC, abstractmethod
from enum import Enum
from typing import Union
import numpy as np
from supervision.detection.core import Detections
from supervision.draw.color import Color, ColorPalette
class ColorMap(Enum):
"""
Enum for annotator color mapping.
"""
INDEX = "index"
CLASS = "class"
TRACK = "track"
def resolve_color_idx(
detections: Detections, detection_idx: int, color_map: ColorMap = ColorMap.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 color_map == ColorMap.INDEX:
return detection_idx
elif color_map == ColorMap.CLASS:
if detections.class_id is None:
raise ValueError(
"Could not resolve color by class because"
"Detections do not have class_id"
)
return detections.class_id[detection_idx]
elif color_map == ColorMap.TRACK:
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 resolve_color(color: Union[Color, ColorPalette], idx: int) -> Color:
if isinstance(color, ColorPalette):
return color.by_idx(idx)
else:
return color
class BaseAnnotator(ABC):
+681 -57
View File
@@ -1,14 +1,11 @@
from typing import List, Tuple, Union
from math import sqrt
from typing import List, Optional, Tuple, Union
import cv2
import numpy as np
from supervision.annotators.base import (
BaseAnnotator,
ColorMap,
resolve_color,
resolve_color_idx,
)
from supervision.annotators.base import BaseAnnotator
from supervision.annotators.utils import ColorLookup, Trace, resolve_color
from supervision.detection.core import Detections
from supervision.draw.color import Color, ColorPalette
from supervision.geometry.core import Position
@@ -23,27 +20,34 @@ class BoundingBoxAnnotator(BaseAnnotator):
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
thickness: int = 2,
color_map: str = "class",
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color or color palette to use for
annotating detections.
thickness (int): Thickness of the bounding box lines.
color_map (str): Strategy for mapping colors to annotations.
Options are `index`, `class`, or `track`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.thickness: int = thickness
self.color_map: ColorMap = ColorMap(color_map)
self.color_lookup: ColorLookup = color_lookup
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with bounding boxes based on the provided detections.
Args:
scene (np.ndarray): The image where bounding boxes will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
@@ -63,16 +67,18 @@ class BoundingBoxAnnotator(BaseAnnotator):
```
![bounding-box-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/bounding-box-annotator-example.png)
supervision-annotator-examples/bounding-box-annotator-example-purple.png)
"""
for detection_idx in range(len(detections)):
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
idx = resolve_color_idx(
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_map=self.color_map,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
color = resolve_color(color=self.color, idx=idx)
cv2.rectangle(
img=scene,
pt1=(x1, y1),
@@ -92,27 +98,34 @@ class MaskAnnotator(BaseAnnotator):
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
opacity: float = 0.5,
color_map: str = "class",
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color or color palette to use for
annotating detections.
opacity (float): Opacity of the overlay mask. Must be between `0` and `1`.
color_map (str): Strategy for mapping colors to annotations.
Options are `index`, `class`, or `track`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.opacity = opacity
self.color_map: ColorMap = ColorMap(color_map)
self.color_lookup: ColorLookup = color_lookup
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with masks based on the provided detections.
Args:
scene (np.ndarray): The image where masks will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
@@ -132,27 +145,201 @@ class MaskAnnotator(BaseAnnotator):
```
![mask-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/mask-annotator-example.png)
supervision-annotator-examples/mask-annotator-example-purple.png)
"""
if detections.mask is None:
return scene
for detection_idx in np.flip(np.argsort(detections.area)):
idx = resolve_color_idx(
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_map=self.color_map,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
color = resolve_color(color=self.color, idx=idx)
mask = detections.mask[detection_idx]
colored_mask = np.zeros_like(scene, dtype=np.uint8)
colored_mask[:] = color.as_bgr()
scene[mask] = cv2.addWeighted(
colored_mask, self.opacity, scene, 1 - self.opacity, 0
)[mask]
scene = np.where(
np.expand_dims(mask, axis=-1),
np.uint8(self.opacity * colored_mask + (1 - self.opacity) * scene),
scene,
return scene
class BoxMaskAnnotator(BaseAnnotator):
"""
A class for drawing box masks on an image using provided detections.
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
opacity: float = 0.5,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color or color palette to use for
annotating detections.
opacity (float): Opacity of the overlay mask. Must be between `0` and `1`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.color_lookup: ColorLookup = color_lookup
self.opacity = opacity
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with box masks based on the provided detections.
Args:
scene (np.ndarray): The image where bounding boxes will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
Example:
```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
... )
```
![box-mask-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/box-mask-annotator-example-purple.png)
"""
mask_image = scene.copy()
for detection_idx in range(len(detections)):
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
cv2.rectangle(
img=scene,
pt1=(x1, y1),
pt2=(x2, y2),
color=color.as_bgr(),
thickness=-1,
)
scene = cv2.addWeighted(
scene, self.opacity, mask_image, 1 - self.opacity, gamma=0
)
return scene
class HaloAnnotator(BaseAnnotator):
"""
A class for drawing Halos on an image using provided detections.
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
opacity: float = 0.8,
kernel_size: int = 40,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color or color palette to use for
annotating detections.
opacity (float): Opacity of the overlay mask. Must be between `0` and `1`.
kernel_size (int): The size of the average pooling kernel used for creating
the halo.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.opacity = opacity
self.color_lookup: ColorLookup = color_lookup
self.kernel_size: int = kernel_size
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with halos based on the provided detections.
Args:
scene (np.ndarray): The image where masks will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
Example:
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> halo_annotator = sv.HaloAnnotator()
>>> annotated_frame = halo_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
![halo-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/halo-annotator-example-purple.png)
"""
if detections.mask is None:
return scene
colored_mask = np.zeros_like(scene, dtype=np.uint8)
fmask = np.array([False] * scene.shape[0] * scene.shape[1]).reshape(
scene.shape[0], scene.shape[1]
)
for detection_idx in np.flip(np.argsort(detections.area)):
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
mask = detections.mask[detection_idx]
fmask = np.logical_or(fmask, mask)
color_bgr = color.as_bgr()
colored_mask[mask] = color_bgr
colored_mask = cv2.blur(colored_mask, (self.kernel_size, self.kernel_size))
colored_mask[fmask] = [0, 0, 0]
gray = cv2.cvtColor(colored_mask, cv2.COLOR_BGR2GRAY)
alpha = self.opacity * gray / gray.max()
alpha_mask = alpha[:, :, np.newaxis]
scene = np.uint8(scene * (1 - alpha_mask) + colored_mask * self.opacity)
return scene
@@ -167,7 +354,7 @@ class EllipseAnnotator(BaseAnnotator):
thickness: int = 2,
start_angle: int = -45,
end_angle: int = 235,
color_map: str = "class",
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
@@ -176,22 +363,29 @@ class EllipseAnnotator(BaseAnnotator):
thickness (int): Thickness of the ellipse lines.
start_angle (int): Starting angle of the ellipse.
end_angle (int): Ending angle of the ellipse.
color_map (str): Strategy for mapping colors to annotations.
Options are `index`, `class`, or `track`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.thickness: int = thickness
self.start_angle: int = start_angle
self.end_angle: int = end_angle
self.color_map: ColorMap = ColorMap(color_map)
self.color_lookup: ColorLookup = color_lookup
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with ellipses based on the provided detections.
Args:
scene (np.ndarray): The image where ellipses will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
@@ -211,17 +405,18 @@ class EllipseAnnotator(BaseAnnotator):
```
![ellipse-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/ellipse-annotator-example.png)
supervision-annotator-examples/ellipse-annotator-example-purple.png)
"""
for detection_idx in range(len(detections)):
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
idx = resolve_color_idx(
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_map=self.color_map,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
color = resolve_color(color=self.color, idx=idx)
center = (int((x1 + x2) / 2), y2)
width = x2 - x1
cv2.ellipse(
@@ -247,8 +442,8 @@ class BoxCornerAnnotator(BaseAnnotator):
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
thickness: int = 4,
corner_length: int = 25,
color_map: str = "class",
corner_length: int = 15,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
@@ -256,21 +451,28 @@ class BoxCornerAnnotator(BaseAnnotator):
annotating detections.
thickness (int): Thickness of the corner lines.
corner_length (int): Length of each corner line.
color_map (str): Strategy for mapping colors to annotations.
Options are `index`, `class`, or `track`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.thickness: int = thickness
self.corner_length: int = corner_length
self.color_map: ColorMap = ColorMap(color_map)
self.color_lookup: ColorLookup = color_lookup
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with box corners based on the provided detections.
Args:
scene (np.ndarray): The image where box corners will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
@@ -290,16 +492,18 @@ class BoxCornerAnnotator(BaseAnnotator):
```
![box-corner-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/box-corner-annotator-example.png)
supervision-annotator-examples/box-corner-annotator-example-purple.png)
"""
for detection_idx in range(len(detections)):
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
idx = resolve_color_idx(
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_map=self.color_map,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
color = resolve_color(color=self.color, idx=idx)
corners = [(x1, y1), (x2, y1), (x1, y2), (x2, y2)]
for x, y in corners:
@@ -315,6 +519,166 @@ class BoxCornerAnnotator(BaseAnnotator):
return scene
class CircleAnnotator(BaseAnnotator):
"""
A class for drawing circle on an image using provided detections.
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
thickness: int = 2,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color or color palette to use for
annotating detections.
thickness (int): Thickness of the circle line.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.thickness: int = thickness
self.color_lookup: ColorLookup = color_lookup
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with circles based on the provided detections.
Args:
scene (np.ndarray): The image where box corners will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
Example:
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> circle_annotator = sv.CircleAnnotator()
>>> annotated_frame = circle_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
![circle-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/circle-annotator-example-purple.png)
"""
for detection_idx in range(len(detections)):
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
center = ((x1 + x2) // 2, (y1 + y2) // 2)
distance = sqrt((x1 - center[0]) ** 2 + (y1 - center[1]) ** 2)
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
cv2.circle(
img=scene,
center=center,
radius=int(distance),
color=color.as_bgr(),
thickness=self.thickness,
)
return scene
class DotAnnotator(BaseAnnotator):
"""
A class for drawing dots on an image at specific coordinates based on provided
detections.
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
radius: int = 4,
position: Position = Position.CENTER,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color or color palette to use for
annotating detections.
radius (int): Radius of the drawn dots.
position (Position): The anchor position for placing the dot.
color_lookup (ColorLookup): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.radius: int = radius
self.position: Position = position
self.color_lookup: ColorLookup = color_lookup
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with dots based on the provided detections.
Args:
scene (np.ndarray): The image where dots will be drawn.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
Example:
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> dot_annotator = sv.DotAnnotator()
>>> annotated_frame = dot_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
![dot-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/dot-annotator-example-purple.png)
"""
xy = detections.get_anchor_coordinates(anchor=self.position)
for detection_idx in range(len(detections)):
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
center = (int(xy[detection_idx, 0]), int(xy[detection_idx, 1]))
cv2.circle(scene, center, self.radius, color.as_bgr(), -1)
return scene
class LabelAnnotator:
"""
A class for annotating labels on an image using provided detections.
@@ -328,7 +692,7 @@ class LabelAnnotator:
text_thickness: int = 1,
text_padding: int = 10,
text_position: Position = Position.TOP_LEFT,
color_map: str = "class",
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
@@ -340,8 +704,8 @@ class LabelAnnotator:
text_padding (int): Padding around the text within its background box.
text_position (Position): Position of the text relative to the detection.
Possible values are defined in the `Position` enum.
color_map (str): Strategy for mapping colors to annotations.
Options are `index`, `class`, or `track`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.text_color: Color = text_color
@@ -349,7 +713,7 @@ class LabelAnnotator:
self.text_thickness: int = text_thickness
self.text_padding: int = text_padding
self.text_position: Position = text_position
self.color_map: ColorMap = ColorMap(color_map)
self.color_lookup: ColorLookup = color_lookup
@staticmethod
def resolve_text_background_xyxy(
@@ -398,6 +762,7 @@ class LabelAnnotator:
scene: np.ndarray,
detections: Detections,
labels: List[str] = None,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Annotates the given scene with labels based on the provided detections.
@@ -406,6 +771,8 @@ class LabelAnnotator:
scene (np.ndarray): The image where labels will be drawn.
detections (Detections): Object detections to annotate.
labels (List[str]): Optional. Custom labels for each detection.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The annotated image.
@@ -425,17 +792,19 @@ class LabelAnnotator:
```
![label-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/label-annotator-example-2.png)
supervision-annotator-examples/label-annotator-example-purple.png)
"""
font = cv2.FONT_HERSHEY_SIMPLEX
for detection_idx in range(len(detections)):
detection_xyxy = detections.xyxy[detection_idx].astype(int)
idx = resolve_color_idx(
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_map=self.color_map,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
color = resolve_color(color=self.color, idx=idx)
text = (
f"{detections.class_id[detection_idx]}"
if (labels is None or len(detections) != len(labels))
@@ -476,3 +845,258 @@ class LabelAnnotator:
lineType=cv2.LINE_AA,
)
return scene
class BlurAnnotator(BaseAnnotator):
"""
A class for blurring regions in an image using provided detections.
"""
def __init__(self, kernel_size: int = 15):
"""
Args:
kernel_size (int): The size of the average pooling kernel used for blurring.
"""
self.kernel_size: int = kernel_size
def annotate(
self,
scene: np.ndarray,
detections: Detections,
) -> np.ndarray:
"""
Annotates the given scene by blurring regions based on the provided detections.
Args:
scene (np.ndarray): The image where blurring will be applied.
detections (Detections): Object detections to annotate.
Returns:
np.ndarray: The annotated image.
Example:
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> blur_annotator = sv.BlurAnnotator()
>>> annotated_frame = blur_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
![blur-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/blur-annotator-example-purple.png)
"""
for detection_idx in range(len(detections)):
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
roi = scene[y1:y2, x1:x2]
roi = cv2.blur(roi, (self.kernel_size, self.kernel_size))
scene[y1:y2, x1:x2] = roi
return scene
class TraceAnnotator:
"""
A class for drawing trace paths on an image based on detection coordinates.
!!! warning
This annotator utilizes the `tracker_id`. Read
[here](https://supervision.roboflow.com/trackers/) to learn how to plug
tracking into your inference pipeline.
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
position: Position = Position.CENTER,
trace_length: int = 30,
thickness: int = 2,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
color (Union[Color, ColorPalette]): The color to draw the trace, can be
a single color or a color palette.
position (Position): The position of the trace.
Defaults to `CENTER`.
trace_length (int): The maximum length of the trace in terms of historical
points. Defaults to `30`.
thickness (int): The thickness of the trace lines. Defaults to `2`.
color_lookup (str): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACE`.
"""
self.color: Union[Color, ColorPalette] = color
self.position = position
self.trace = Trace(max_size=trace_length)
self.thickness = thickness
self.color_lookup: ColorLookup = color_lookup
def annotate(
self,
scene: np.ndarray,
detections: Detections,
custom_color_lookup: Optional[np.ndarray] = None,
) -> np.ndarray:
"""
Draws trace paths on the frame based on the detection coordinates provided.
Args:
scene (np.ndarray): The image on which the traces will be drawn.
detections (Detections): The detections which include coordinates for
which the traces will be drawn.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
np.ndarray: The image with the trace paths drawn on it.
Example:
```python
>>> import supervision as sv
>>> from ultralytics import YOLO
>>> model = YOLO('yolov8x.pt')
>>> trace_annotator = sv.TraceAnnotator()
>>> video_info = sv.VideoInfo.from_video_path(video_path='...')
>>> frames_generator = sv.get_video_frames_generator(source_path='...')
>>> tracker = sv.ByteTrack()
>>> with sv.VideoSink(target_path='...', video_info=video_info) as sink:
... for frame in frames_generator:
... result = model(frame)[0]
... detections = sv.Detections.from_ultralytics(result)
... detections = tracker.update_with_detections(detections)
... annotated_frame = trace_annotator.annotate(
... scene=frame.copy(),
... detections=detections)
... sink.write_frame(frame=annotated_frame)
```
![trace-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/trace-annotator-example-purple.png)
"""
self.trace.put(detections)
for detection_idx in range(len(detections)):
tracker_id = int(detections.tracker_id[detection_idx])
color = resolve_color(
color=self.color,
detections=detections,
detection_idx=detection_idx,
color_lookup=self.color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
xy = self.trace.get(tracker_id=tracker_id)
if len(xy) > 1:
scene = cv2.polylines(
scene,
[xy.astype(np.int32)],
False,
color=color.as_bgr(),
thickness=self.thickness,
)
return scene
class HeatMapAnnotator:
"""
A class for drawing heatmaps on an image based on provided detections.
Heat accumulates over time and is drawn as a semi-transparent overlay
of blurred circles.
"""
def __init__(
self,
position: Position = Position.BOTTOM_CENTER,
opacity: float = 0.2,
radius: int = 40,
kernel_size: int = 25,
top_hue: int = 0,
low_hue: int = 125,
):
"""
Args:
position (Position): The position of the heatmap. Defaults to
`BOTTOM_CENTER`.
opacity (float): Opacity of the overlay mask, between 0 and 1.
radius (int): Radius of the heat circle.
kernel_size (int): Kernel size for blurring the heatmap.
top_hue (int): Hue at the top of the heatmap. Defaults to 0 (red).
low_hue (int): Hue at the bottom of the heatmap. Defaults to 125 (blue).
"""
self.position = position
self.opacity = opacity
self.radius = radius
self.kernel_size = kernel_size
self.heat_mask = None
self.top_hue = top_hue
self.low_hue = low_hue
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
"""
Annotates the scene with a heatmap based on the provided detections.
Args:
scene (np.ndarray): The image where the heatmap will be drawn.
detections (Detections): Object detections to annotate.
Returns:
np.ndarray: Annotated image.
Example:
```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)
```
![heatmap-annotator-example](https://media.roboflow.com/
supervision-annotator-examples/heat-map-annotator-example-purple.png)
"""
if self.heat_mask is None:
self.heat_mask = np.zeros(scene.shape[:2])
mask = np.zeros(scene.shape[:2])
for xy in detections.get_anchor_coordinates(self.position):
cv2.circle(mask, (int(xy[0]), int(xy[1])), self.radius, 1, -1)
self.heat_mask = mask + self.heat_mask
temp = self.heat_mask.copy()
temp = self.low_hue - temp / temp.max() * (self.low_hue - self.top_hue)
temp = temp.astype(np.uint8)
if self.kernel_size is not None:
temp = cv2.blur(temp, (self.kernel_size, self.kernel_size))
hsv = np.zeros(scene.shape)
hsv[..., 0] = temp
hsv[..., 1] = 255
hsv[..., 2] = 255
temp = cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR)
mask = cv2.cvtColor(self.heat_mask.astype(np.uint8), cv2.COLOR_GRAY2BGR) > 0
scene[mask] = cv2.addWeighted(temp, self.opacity, scene, 1 - self.opacity, 0)[
mask
]
return scene
+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:
-114
View File
@@ -5,7 +5,6 @@ import numpy as np
from supervision.detection.core import Detections
from supervision.draw.color import Color, ColorPalette
from supervision.geometry.core import Position
class BoxAnnotator:
@@ -145,116 +144,3 @@ class BoxAnnotator:
lineType=cv2.LINE_AA,
)
return scene
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]
class TraceAnnotator:
"""
A class for drawing trace paths on an image based on detection coordinates.
Attributes:
color (Union[Color, ColorPalette]): The color to draw the trace, can be
a single color or a color palette.
position (Optional[Position]): The position of the trace. Defaults to `CENTER`.
trace_length (int): The maximum length of the trace in terms of historical
points. Defaults to `30`.
thickness (int): The thickness of the trace lines. Defaults to `2`.
"""
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
position: Optional[Position] = Position.CENTER,
trace_length: int = 30,
thickness: int = 2,
):
self.color: Union[Color, ColorPalette] = color
self.position = position
self.trace = Trace(max_size=trace_length)
self.thickness = thickness
def annotate(self, scene: np.ndarray, detections: Detections) -> np.ndarray:
"""
Draws trace paths on the frame based on the detection coordinates provided.
Args:
scene (np.ndarray): The image on which the traces will be drawn.
detections (Detections): The detections which include coordinates for
which the traces will be drawn.
Returns:
np.ndarray: The image with the trace paths drawn on it.
Example:
```python
>>> import supervision as sv
>>> image = ...
>>> detections = sv.Detections(...)
>>> trace_annotator = sv.TraceAnnotator()
>>> annotated_frame = trace_annotator.annotate(
... scene=image.copy(),
... detections=detections
... )
```
"""
self.trace.put(detections)
for i, (xyxy, mask, confidence, class_id, tracker_id) in enumerate(detections):
class_id = detections.class_id[i] if 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
)
xy = self.trace.get(tracker_id=tracker_id)
if len(xy) > 1:
scene = cv2.polylines(
scene,
[xy.astype(np.int32)],
False,
color=color.as_bgr(),
thickness=self.thickness,
)
return scene
+7 -49
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:
@@ -185,46 +184,6 @@ class Detections:
class_id=yolov5_detections_predictions[:, 5].astype(int),
)
@classmethod
@deprecated(
"""
This method is deprecated and removed in 0.15.0 release.
Use sv.Detections.from_ultralytics() instead as it is more generic and
can be used for detections from any ultralytics.engine.results.Results Object
"""
)
def from_yolov8(cls, yolov8_results) -> Detections:
"""
Creates a Detections instance from a
[YOLOv8](https://github.com/ultralytics/ultralytics) inference result.
Args:
yolov8_results (ultralytics.yolo.engine.results.Results):
The output Results instance from YOLOv8
Returns:
Detections: A new Detections object.
Example:
```python
>>> import cv2
>>> from ultralytics import YOLO
>>> import supervision as sv
>>> image = cv2.imread(SOURCE_IMAGE_PATH)
>>> model = YOLO('yolov8s.pt')
>>> result = model(image)[0]
>>> detections = sv.Detections.from_yolov8(result)
```
"""
return cls(
xyxy=yolov8_results.boxes.xyxy.cpu().numpy(),
confidence=yolov8_results.boxes.conf.cpu().numpy(),
class_id=yolov8_results.boxes.cls.cpu().numpy().astype(int),
mask=extract_ultralytics_masks(yolov8_results),
)
@classmethod
def from_ultralytics(cls, ultralytics_results) -> Detections:
"""
@@ -296,7 +255,7 @@ class Detections:
>>> detections = sv.Detections.from_yolo_nas(result)
```
"""
if np.asarray(yolo_nas_results.bboxes_xyxy).shape[0] == 0:
if np.asarray(yolo_nas_results.prediction.bboxes_xyxy).shape[0] == 0:
return cls.empty()
return cls(
@@ -432,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.
@@ -440,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,
@@ -458,19 +415,19 @@ 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
)
if np.asarray(xyxy).shape[0] == 0:
@@ -481,6 +438,7 @@ class Detections:
confidence=confidence,
class_id=class_id,
mask=masks,
tracker_id=trackers,
)
@classmethod
+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:
+34 -10
View File
@@ -1,3 +1,4 @@
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Callable, Optional, Tuple
import numpy as np
@@ -28,15 +29,16 @@ class InferenceSlicer:
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
@@ -51,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:
@@ -98,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],
+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
+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
+58 -6
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
@@ -71,13 +73,11 @@ class VideoSink:
```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,
codec='H264') 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)
```
"""
@@ -202,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()
@@ -2,14 +2,15 @@ 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.core import ColorMap, resolve_color_idx
from supervision.annotators.utils import ColorLookup, resolve_color_idx
from supervision.detection.core import Detections
@pytest.mark.parametrize(
"detections, detection_idx, color_map, expected_result, exception",
"detections, detection_idx, color_lookup, expected_result, exception",
[
(
mock_detections(
@@ -18,10 +19,10 @@ from supervision.detection.core import Detections
tracker_id=[2, 6],
),
0,
ColorMap.INDEX,
ColorLookup.INDEX,
0,
DoesNotRaise(),
), # multiple detections; index mapping
), # multiple detections; index lookup
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
@@ -29,10 +30,10 @@ from supervision.detection.core import Detections
tracker_id=[2, 6],
),
0,
ColorMap.CLASS,
ColorLookup.CLASS,
5,
DoesNotRaise(),
), # multiple detections; class mapping
), # multiple detections; class lookup
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
@@ -40,17 +41,17 @@ from supervision.detection.core import Detections
tracker_id=[2, 6],
),
0,
ColorMap.TRACK,
ColorLookup.TRACK,
2,
DoesNotRaise(),
), # multiple detections; track mapping
), # multiple detections; track lookup
(
Detections.empty(),
0,
ColorMap.INDEX,
ColorLookup.INDEX,
None,
pytest.raises(ValueError),
), # no detections; index mapping; out of bounds
), # no detections; index lookup; out of bounds
(
mock_detections(
xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]],
@@ -58,30 +59,44 @@ from supervision.detection.core import Detections
tracker_id=[2, 6],
),
2,
ColorMap.INDEX,
ColorLookup.INDEX,
None,
pytest.raises(ValueError),
), # multiple detections; index mapping; out of bounds
), # multiple detections; index lookup; out of bounds
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
0,
ColorMap.CLASS,
ColorLookup.CLASS,
None,
pytest.raises(ValueError),
), # multiple detections; class mapping; no class_id
), # multiple detections; class lookup; no class_id
(
mock_detections(xyxy=[[10, 10, 20, 20], [20, 20, 30, 30]]),
0,
ColorMap.TRACK,
ColorLookup.TRACK,
None,
pytest.raises(ValueError),
), # multiple detections; class mapping; no track_id
), # 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_map: ColorMap,
color_lookup: ColorLookup,
expected_result: Optional[int],
exception: Exception,
) -> None:
@@ -89,6 +104,6 @@ def test_resolve_color_idx(
result = resolve_color_idx(
detections=detections,
detection_idx=detection_idx,
color_map=color_map,
color_lookup=color_lookup,
)
assert 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(