diff --git a/.github/workflows/clear-cache.yml b/.github/workflows/clear-cache.yml
index 76aed5cf..5b96de42 100644
--- a/.github/workflows/clear-cache.yml
+++ b/.github/workflows/clear-cache.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clear cache
- uses: actions/github-script@v6
+ uses: actions/github-script@v7
with:
script: |
console.log("About to clear")
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e264874b..4e96f7ee 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,6 +11,7 @@ repos:
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
+ exclude: test/.*\.py
- id: check-yaml
- id: check-docstring-first
- id: check-executables-have-shebangs
@@ -65,12 +66,12 @@ repos:
- repo: https://github.com/psf/black
- rev: 23.10.1
+ rev: 23.11.0
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.1.3
+ rev: v0.1.5
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
diff --git a/README.md b/README.md
index 78d8fbf0..3a95ff13 100644
--- a/README.md
+++ b/README.md
@@ -24,10 +24,6 @@
-
-
-
-
## 👋 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! 🤝
diff --git a/docs/annotators.md b/docs/annotators.md
index efb77d11..7dd8124d 100644
--- a/docs/annotators.md
+++ b/docs/annotators.md
@@ -166,6 +166,27 @@
+=== "Polygon"
+
+ ```python
+ >>> import supervision as sv
+
+ >>> image = ...
+ >>> detections = sv.Detections(...)
+
+ >>> polygon_annotator = sv.PolygonAnnotator()
+ >>> annotated_frame = polygon_annotator.annotate(
+ ... scene=image.copy(),
+ ... detections=detections
+ ... )
+ ```
+
+
+
+ { align=center width="800" }
+
+
+
=== "Label"
```python
@@ -304,6 +325,10 @@
:::supervision.annotators.core.MaskAnnotator
+## PolygonAnnotator
+
+:::supervision.annotators.core.PolygonAnnotator
+
## LabelAnnotator
:::supervision.annotators.core.LabelAnnotator
diff --git a/poetry.lock b/poetry.lock
index 401f8e30..f8795a47 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -206,29 +206,29 @@ lxml = ["lxml"]
[[package]]
name = "black"
-version = "23.10.1"
+version = "23.11.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
files = [
- {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"},
- {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"},
- {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"},
- {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"},
- {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"},
- {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"},
- {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"},
- {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"},
- {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"},
- {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"},
- {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"},
- {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"},
- {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"},
- {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"},
- {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"},
- {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"},
- {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"},
- {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"},
+ {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"},
+ {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"},
+ {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"},
+ {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"},
+ {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"},
+ {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"},
+ {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"},
+ {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"},
+ {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"},
+ {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"},
+ {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"},
+ {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"},
+ {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"},
+ {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"},
+ {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"},
+ {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"},
+ {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"},
+ {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"},
]
[package.dependencies]
@@ -1837,13 +1837,13 @@ mkdocs = ">=1.1"
[[package]]
name = "mkdocs-material"
-version = "9.4.7"
+version = "9.4.8"
description = "Documentation that simply works"
optional = false
python-versions = ">=3.8"
files = [
- {file = "mkdocs_material-9.4.7-py3-none-any.whl", hash = "sha256:4d698d52bb6a6a3c452ab854481c4cdb68453a0420956a6aee2de55fe15fe610"},
- {file = "mkdocs_material-9.4.7.tar.gz", hash = "sha256:e704e001c9ef17291e1d3462c202425217601653e18f68f85d28eff4690e662b"},
+ {file = "mkdocs_material-9.4.8-py3-none-any.whl", hash = "sha256:8b20f6851bddeef37dced903893cd176cf13a21a482e97705a103c45f06ce9b9"},
+ {file = "mkdocs_material-9.4.8.tar.gz", hash = "sha256:f0c101453e8bc12b040e8b64ca39a405d950d8402609b1378cc2b98976e74b5f"},
]
[package.dependencies]
@@ -1877,23 +1877,25 @@ files = [
[[package]]
name = "mkdocstrings"
-version = "0.23.0"
+version = "0.24.0"
description = "Automatic documentation from sources, for MkDocs."
optional = false
python-versions = ">=3.8"
files = [
- {file = "mkdocstrings-0.23.0-py3-none-any.whl", hash = "sha256:051fa4014dfcd9ed90254ae91de2dbb4f24e166347dae7be9a997fe16316c65e"},
- {file = "mkdocstrings-0.23.0.tar.gz", hash = "sha256:d9c6a37ffbe7c14a7a54ef1258c70b8d394e6a33a1c80832bce40b9567138d1c"},
+ {file = "mkdocstrings-0.24.0-py3-none-any.whl", hash = "sha256:f4908560c10f587326d8f5165d1908817b2e280bbf707607f601c996366a2264"},
+ {file = "mkdocstrings-0.24.0.tar.gz", hash = "sha256:222b1165be41257b494a9d29b14135d2b7ca43f38161d5b10caae03b87bd4f7e"},
]
[package.dependencies]
+click = ">=7.0"
importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
Jinja2 = ">=2.11.1"
Markdown = ">=3.3"
MarkupSafe = ">=1.1"
-mkdocs = ">=1.2"
+mkdocs = ">=1.4"
mkdocs-autorefs = ">=0.3.1"
mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
+platformdirs = ">=2.2.0"
pymdown-extensions = ">=6.3"
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.10\""}
@@ -1930,38 +1932,38 @@ files = [
[[package]]
name = "mypy"
-version = "1.6.1"
+version = "1.7.0"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "mypy-1.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e5012e5cc2ac628177eaac0e83d622b2dd499e28253d4107a08ecc59ede3fc2c"},
- {file = "mypy-1.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8fbb68711905f8912e5af474ca8b78d077447d8f3918997fecbf26943ff3cbb"},
- {file = "mypy-1.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a1ad938fee7d2d96ca666c77b7c494c3c5bd88dff792220e1afbebb2925b5e"},
- {file = "mypy-1.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b96ae2c1279d1065413965c607712006205a9ac541895004a1e0d4f281f2ff9f"},
- {file = "mypy-1.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:40b1844d2e8b232ed92e50a4bd11c48d2daa351f9deee6c194b83bf03e418b0c"},
- {file = "mypy-1.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81af8adaa5e3099469e7623436881eff6b3b06db5ef75e6f5b6d4871263547e5"},
- {file = "mypy-1.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8c223fa57cb154c7eab5156856c231c3f5eace1e0bed9b32a24696b7ba3c3245"},
- {file = "mypy-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8032e00ce71c3ceb93eeba63963b864bf635a18f6c0c12da6c13c450eedb183"},
- {file = "mypy-1.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4c46b51de523817a0045b150ed11b56f9fff55f12b9edd0f3ed35b15a2809de0"},
- {file = "mypy-1.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:19f905bcfd9e167159b3d63ecd8cb5e696151c3e59a1742e79bc3bcb540c42c7"},
- {file = "mypy-1.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:82e469518d3e9a321912955cc702d418773a2fd1e91c651280a1bda10622f02f"},
- {file = "mypy-1.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d4473c22cc296425bbbce7e9429588e76e05bc7342da359d6520b6427bf76660"},
- {file = "mypy-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59a0d7d24dfb26729e0a068639a6ce3500e31d6655df8557156c51c1cb874ce7"},
- {file = "mypy-1.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cfd13d47b29ed3bbaafaff7d8b21e90d827631afda134836962011acb5904b71"},
- {file = "mypy-1.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:eb4f18589d196a4cbe5290b435d135dee96567e07c2b2d43b5c4621b6501531a"},
- {file = "mypy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:41697773aa0bf53ff917aa077e2cde7aa50254f28750f9b88884acea38a16169"},
- {file = "mypy-1.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7274b0c57737bd3476d2229c6389b2ec9eefeb090bbaf77777e9d6b1b5a9d143"},
- {file = "mypy-1.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbaf4662e498c8c2e352da5f5bca5ab29d378895fa2d980630656178bd607c46"},
- {file = "mypy-1.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bb8ccb4724f7d8601938571bf3f24da0da791fe2db7be3d9e79849cb64e0ae85"},
- {file = "mypy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:68351911e85145f582b5aa6cd9ad666c8958bcae897a1bfda8f4940472463c45"},
- {file = "mypy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:49ae115da099dcc0922a7a895c1eec82c1518109ea5c162ed50e3b3594c71208"},
- {file = "mypy-1.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b27958f8c76bed8edaa63da0739d76e4e9ad4ed325c814f9b3851425582a3cd"},
- {file = "mypy-1.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:925cd6a3b7b55dfba252b7c4561892311c5358c6b5a601847015a1ad4eb7d332"},
- {file = "mypy-1.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8f57e6b6927a49550da3d122f0cb983d400f843a8a82e65b3b380d3d7259468f"},
- {file = "mypy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a43ef1c8ddfdb9575691720b6352761f3f53d85f1b57d7745701041053deff30"},
- {file = "mypy-1.6.1-py3-none-any.whl", hash = "sha256:4cbe68ef919c28ea561165206a2dcb68591c50f3bcf777932323bc208d949cf1"},
- {file = "mypy-1.6.1.tar.gz", hash = "sha256:4d01c00d09a0be62a4ca3f933e315455bde83f37f892ba4b08ce92f3cf44bcc1"},
+ {file = "mypy-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5da84d7bf257fd8f66b4f759a904fd2c5a765f70d8b52dde62b521972a0a2357"},
+ {file = "mypy-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a3637c03f4025f6405737570d6cbfa4f1400eb3c649317634d273687a09ffc2f"},
+ {file = "mypy-1.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b633f188fc5ae1b6edca39dae566974d7ef4e9aaaae00bc36efe1f855e5173ac"},
+ {file = "mypy-1.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed9a3997b90c6f891138e3f83fb8f475c74db4ccaa942a1c7bf99e83a989a1"},
+ {file = "mypy-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fe46e96ae319df21359c8db77e1aecac8e5949da4773c0274c0ef3d8d1268a9"},
+ {file = "mypy-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:df67fbeb666ee8828f675fee724cc2cbd2e4828cc3df56703e02fe6a421b7401"},
+ {file = "mypy-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a79cdc12a02eb526d808a32a934c6fe6df07b05f3573d210e41808020aed8b5d"},
+ {file = "mypy-1.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f65f385a6f43211effe8c682e8ec3f55d79391f70a201575def73d08db68ead1"},
+ {file = "mypy-1.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e81ffd120ee24959b449b647c4b2fbfcf8acf3465e082b8d58fd6c4c2b27e46"},
+ {file = "mypy-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:f29386804c3577c83d76520abf18cfcd7d68264c7e431c5907d250ab502658ee"},
+ {file = "mypy-1.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:87c076c174e2c7ef8ab416c4e252d94c08cd4980a10967754f91571070bf5fbe"},
+ {file = "mypy-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cb8d5f6d0fcd9e708bb190b224089e45902cacef6f6915481806b0c77f7786d"},
+ {file = "mypy-1.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93e76c2256aa50d9c82a88e2f569232e9862c9982095f6d54e13509f01222fc"},
+ {file = "mypy-1.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cddee95dea7990e2215576fae95f6b78a8c12f4c089d7e4367564704e99118d3"},
+ {file = "mypy-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:d01921dbd691c4061a3e2ecdbfbfad029410c5c2b1ee88946bf45c62c6c91210"},
+ {file = "mypy-1.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:185cff9b9a7fec1f9f7d8352dff8a4c713b2e3eea9c6c4b5ff7f0edf46b91e41"},
+ {file = "mypy-1.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7b1e399c47b18feb6f8ad4a3eef3813e28c1e871ea7d4ea5d444b2ac03c418"},
+ {file = "mypy-1.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc9fe455ad58a20ec68599139ed1113b21f977b536a91b42bef3ffed5cce7391"},
+ {file = "mypy-1.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d0fa29919d2e720c8dbaf07d5578f93d7b313c3e9954c8ec05b6d83da592e5d9"},
+ {file = "mypy-1.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b53655a295c1ed1af9e96b462a736bf083adba7b314ae775563e3fb4e6795f5"},
+ {file = "mypy-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1b06b4b109e342f7dccc9efda965fc3970a604db70f8560ddfdee7ef19afb05"},
+ {file = "mypy-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf7a2f0a6907f231d5e41adba1a82d7d88cf1f61a70335889412dec99feeb0f8"},
+ {file = "mypy-1.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551d4a0cdcbd1d2cccdcc7cb516bb4ae888794929f5b040bb51aae1846062901"},
+ {file = "mypy-1.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:55d28d7963bef00c330cb6461db80b0b72afe2f3c4e2963c99517cf06454e665"},
+ {file = "mypy-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:870bd1ffc8a5862e593185a4c169804f2744112b4a7c55b93eb50f48e7a77010"},
+ {file = "mypy-1.7.0-py3-none-any.whl", hash = "sha256:96650d9a4c651bc2a4991cf46f100973f656d69edc7faf91844e87fe627f7e96"},
+ {file = "mypy-1.7.0.tar.gz", hash = "sha256:1e280b5697202efa698372d2f39e9a6713a0395a756b1c6bd48995f8d72690dc"},
]
[package.dependencies]
@@ -1972,6 +1974,7 @@ typing-extensions = ">=4.1.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
reports = ["lxml"]
[[package]]
@@ -3262,28 +3265,28 @@ files = [
[[package]]
name = "ruff"
-version = "0.1.3"
-description = "An extremely fast Python linter, written in Rust."
+version = "0.1.5"
+description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.1.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901"},
- {file = "ruff-0.1.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8"},
- {file = "ruff-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d"},
- {file = "ruff-0.1.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20"},
- {file = "ruff-0.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3"},
- {file = "ruff-0.1.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784"},
- {file = "ruff-0.1.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a"},
- {file = "ruff-0.1.3-py3-none-win32.whl", hash = "sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef"},
- {file = "ruff-0.1.3-py3-none-win_amd64.whl", hash = "sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea"},
- {file = "ruff-0.1.3-py3-none-win_arm64.whl", hash = "sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f"},
- {file = "ruff-0.1.3.tar.gz", hash = "sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34"},
+ {file = "ruff-0.1.5-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:32d47fc69261c21a4c48916f16ca272bf2f273eb635d91c65d5cd548bf1f3d96"},
+ {file = "ruff-0.1.5-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:171276c1df6c07fa0597fb946139ced1c2978f4f0b8254f201281729981f3c17"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ef33cd0bb7316ca65649fc748acc1406dfa4da96a3d0cde6d52f2e866c7b39"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b2c205827b3f8c13b4a432e9585750b93fd907986fe1aec62b2a02cf4401eee6"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb408e3a2ad8f6881d0f2e7ad70cddb3ed9f200eb3517a91a245bbe27101d379"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f20dc5e5905ddb407060ca27267c7174f532375c08076d1a953cf7bb016f5a24"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aafb9d2b671ed934998e881e2c0f5845a4295e84e719359c71c39a5363cccc91"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4894dddb476597a0ba4473d72a23151b8b3b0b5f958f2cf4d3f1c572cdb7af7"},
+ {file = "ruff-0.1.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00a7ec893f665ed60008c70fe9eeb58d210e6b4d83ec6654a9904871f982a2a"},
+ {file = "ruff-0.1.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8c11206b47f283cbda399a654fd0178d7a389e631f19f51da15cbe631480c5b"},
+ {file = "ruff-0.1.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fa29e67b3284b9a79b1a85ee66e293a94ac6b7bb068b307a8a373c3d343aa8ec"},
+ {file = "ruff-0.1.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9b97fd6da44d6cceb188147b68db69a5741fbc736465b5cea3928fdac0bc1aeb"},
+ {file = "ruff-0.1.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:721f4b9d3b4161df8dc9f09aa8562e39d14e55a4dbaa451a8e55bdc9590e20f4"},
+ {file = "ruff-0.1.5-py3-none-win32.whl", hash = "sha256:f80c73bba6bc69e4fdc73b3991db0b546ce641bdcd5b07210b8ad6f64c79f1ab"},
+ {file = "ruff-0.1.5-py3-none-win_amd64.whl", hash = "sha256:c21fe20ee7d76206d290a76271c1af7a5096bc4c73ab9383ed2ad35f852a0087"},
+ {file = "ruff-0.1.5-py3-none-win_arm64.whl", hash = "sha256:82bfcb9927e88c1ed50f49ac6c9728dab3ea451212693fe40d08d314663e412f"},
+ {file = "ruff-0.1.5.tar.gz", hash = "sha256:5cbec0ef2ae1748fb194f420fb03fb2c25c3258c86129af7172ff8f198f125ab"},
]
[[package]]
@@ -3772,4 +3775,4 @@ desktop = ["opencv-python"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.8,<3.12.0"
-content-hash = "7d0396af59b415511fe78241e8b1ba534c14fe83a3e0365aed7fafad63d1cca9"
+content-hash = "f2d0f1827c652b0ae160a093050bca163b13f2d166968893a0c5a02d27bfb856"
diff --git a/pyproject.toml b/pyproject.toml
index dde0f28a..227d6f47 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -57,7 +57,7 @@ pytest = "^7.2.2"
wheel = ">=0.40,<0.42"
notebook = ">=6.5.3,<8.0.0"
build = ">=0.10,<1.1"
-ruff = ">=0.0.280,<0.1.4"
+ruff = ">=0.0.280,<0.1.6"
isort = "^5.12.0"
black = "^23.7.0"
mypy = "^1.4.1"
@@ -67,7 +67,7 @@ flake8 = { version = "*", python = ">=3.8.1,<3.12.0" }
[tool.poetry.group.docs.dependencies]
mkdocs-material = "^9.1.4"
-mkdocstrings = {extras = ["python"], version = ">=0.20,<0.24"}
+mkdocstrings = {extras = ["python"], version = ">=0.20,<0.25"}
[tool.flake8]
exclude = ".venv"
@@ -173,6 +173,7 @@ convention = "google"
"__init__.py" = ["E402","F401"]
"supervision/assets/list.py" = ["E501"]
+
[tool.ruff.pylint]
max-args = 20
diff --git a/supervision/__init__.py b/supervision/__init__.py
index f4e70ead..44f25f7f 100644
--- a/supervision/__init__.py
+++ b/supervision/__init__.py
@@ -18,6 +18,7 @@ from supervision.annotators.core import (
HeatMapAnnotator,
LabelAnnotator,
MaskAnnotator,
+ PolygonAnnotator,
TraceAnnotator,
)
from supervision.annotators.utils import ColorLookup
diff --git a/supervision/annotators/core.py b/supervision/annotators/core.py
index bd5181ab..0e34cc16 100644
--- a/supervision/annotators/core.py
+++ b/supervision/annotators/core.py
@@ -7,8 +7,9 @@ import numpy as np
from supervision.annotators.base import BaseAnnotator
from supervision.annotators.utils import ColorLookup, Trace, resolve_color
from supervision.detection.core import Detections
-from supervision.detection.utils import clip_boxes
+from supervision.detection.utils import clip_boxes, mask_to_polygons
from supervision.draw.color import Color, ColorPalette
+from supervision.draw.utils import draw_polygon
from supervision.geometry.core import Position
@@ -51,7 +52,7 @@ class BoundingBoxAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -93,6 +94,10 @@ class BoundingBoxAnnotator(BaseAnnotator):
class MaskAnnotator(BaseAnnotator):
"""
A class for drawing masks on an image using provided detections.
+
+ !!! warning
+
+ This annotator utilizes the `sv.Detections.mask`.
"""
def __init__(
@@ -129,7 +134,7 @@ class MaskAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -170,6 +175,92 @@ class MaskAnnotator(BaseAnnotator):
return scene
+class PolygonAnnotator(BaseAnnotator):
+ """
+ A class for drawing polygons on an image using provided detections.
+
+ !!! warning
+
+ This annotator utilizes the `sv.Detections.mask`.
+ """
+
+ 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 polygon lines.
+ 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 polygons based on the provided detections.
+
+ Args:
+ scene (np.ndarray): The image where polygons 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:
+ The annotated image.
+
+ Example:
+ ```python
+ >>> import supervision as sv
+
+ >>> image = ...
+ >>> detections = sv.Detections(...)
+
+ >>> polygon_annotator = sv.PolygonAnnotator()
+ >>> annotated_frame = polygon_annotator.annotate(
+ ... scene=image.copy(),
+ ... detections=detections
+ ... )
+ ```
+
+ 
+ """
+ if detections.mask is None:
+ return scene
+
+ for detection_idx in range(len(detections)):
+ mask = detections.mask[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,
+ )
+ for polygon in mask_to_polygons(mask=mask):
+ scene = draw_polygon(
+ scene=scene,
+ polygon=polygon,
+ color=color,
+ thickness=self.thickness,
+ )
+
+ return scene
+
+
class BoxMaskAnnotator(BaseAnnotator):
"""
A class for drawing box masks on an image using provided detections.
@@ -209,7 +300,7 @@ class BoxMaskAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -255,6 +346,10 @@ class BoxMaskAnnotator(BaseAnnotator):
class HaloAnnotator(BaseAnnotator):
"""
A class for drawing Halos on an image using provided detections.
+
+ !!! warning
+
+ This annotator utilizes the `sv.Detections.mask`.
"""
def __init__(
@@ -295,7 +390,7 @@ class HaloAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -389,7 +484,7 @@ class EllipseAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -476,7 +571,7 @@ class BoxCornerAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -560,7 +655,7 @@ class CircleAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -646,7 +741,7 @@ class DotAnnotator(BaseAnnotator):
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -776,7 +871,7 @@ class LabelAnnotator:
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -873,7 +968,7 @@ class BlurAnnotator(BaseAnnotator):
detections (Detections): Object detections to annotate.
Returns:
- np.ndarray: The annotated image.
+ The annotated image.
Example:
```python
@@ -911,7 +1006,7 @@ class TraceAnnotator:
!!! warning
- This annotator utilizes the `tracker_id`. Read
+ This annotator utilizes the `sv.Detections.tracker_id`. Read
[here](https://supervision.roboflow.com/trackers/) to learn how to plug
tracking into your inference pipeline.
"""
@@ -959,7 +1054,7 @@ class TraceAnnotator:
Allows to override the default color mapping strategy.
Returns:
- np.ndarray: The image with the trace paths drawn on it.
+ The annotated image.
Example:
```python
@@ -1055,7 +1150,7 @@ class HeatMapAnnotator:
detections (Detections): Object detections to annotate.
Returns:
- np.ndarray: Annotated image.
+ Annotated image.
Example:
```python
diff --git a/supervision/dataset/formats/yolo.py b/supervision/dataset/formats/yolo.py
index d93b0465..254f034d 100644
--- a/supervision/dataset/formats/yolo.py
+++ b/supervision/dataset/formats/yolo.py
@@ -149,7 +149,7 @@ def load_yolo_annotations(
annotations[image_path] = Detections.empty()
continue
- lines = read_txt_file(str(annotation_path))
+ lines = read_txt_file(file_path=annotation_path, skip_empty=True)
h, w, _ = image.shape
resolution_wh = (w, h)
diff --git a/supervision/utils/file.py b/supervision/utils/file.py
index 3954f9d5..c0521236 100644
--- a/supervision/utils/file.py
+++ b/supervision/utils/file.py
@@ -57,19 +57,24 @@ def list_files_with_extensions(
return files_with_extensions
-def read_txt_file(file_path: str) -> List[str]:
+def read_txt_file(file_path: str, skip_empty: bool = False) -> List[str]:
"""
Read a text file and return a list of strings without newline characters.
+ Optionally skip empty lines.
Args:
file_path (str): The path to the text file.
+ skip_empty (bool): If True, skip lines that are empty or contain only
+ whitespace. Default is False.
Returns:
List[str]: A list of strings representing the lines in the text file.
"""
with open(file_path, "r") as file:
- lines = file.readlines()
- lines = [line.rstrip("\n") for line in lines]
+ if skip_empty:
+ lines = [line.rstrip("\n") for line in file if line.strip()]
+ else:
+ lines = [line.rstrip("\n") for line in file]
return lines
diff --git a/test/annotators/test_utils.py b/test/annotators/test_utils.py
index 98d9be6b..1344d213 100644
--- a/test/annotators/test_utils.py
+++ b/test/annotators/test_utils.py
@@ -1,5 +1,5 @@
from contextlib import ExitStack as DoesNotRaise
-from test.utils import mock_detections
+from test.test_utils import mock_detections
from typing import Optional
import numpy as np
diff --git a/test/dataset/formats/test_pascal_voc.py b/test/dataset/formats/test_pascal_voc.py
index 67d26c57..042748e9 100644
--- a/test/dataset/formats/test_pascal_voc.py
+++ b/test/dataset/formats/test_pascal_voc.py
@@ -1,6 +1,6 @@
import xml.etree.ElementTree as ET
from contextlib import ExitStack as DoesNotRaise
-from test.utils import mock_detections
+from test.test_utils import mock_detections
from typing import List, Optional
import numpy as np
diff --git a/test/dataset/test_core.py b/test/dataset/test_core.py
index 72ae27f3..4a75225c 100644
--- a/test/dataset/test_core.py
+++ b/test/dataset/test_core.py
@@ -1,5 +1,5 @@
from contextlib import ExitStack as DoesNotRaise
-from test.utils import mock_detections
+from test.test_utils import mock_detections
from typing import List, Optional
import numpy as np
diff --git a/test/dataset/test_utils.py b/test/dataset/test_utils.py
index 6d0db2e5..5ca96ca5 100644
--- a/test/dataset/test_utils.py
+++ b/test/dataset/test_utils.py
@@ -1,5 +1,5 @@
from contextlib import ExitStack as DoesNotRaise
-from test.utils import mock_detections
+from test.test_utils import mock_detections
from typing import Dict, List, Optional, Tuple, TypeVar
import pytest
diff --git a/test/detection/test_core.py b/test/detection/test_core.py
index 02595d97..9708f338 100644
--- a/test/detection/test_core.py
+++ b/test/detection/test_core.py
@@ -1,5 +1,5 @@
from contextlib import ExitStack as DoesNotRaise
-from test.utils import mock_detections
+from test.test_utils import mock_detections
from typing import List, Optional, Union
import numpy as np
diff --git a/test/metrics/test_detection.py b/test/metrics/test_detection.py
index 796e6c81..7cb92c46 100644
--- a/test/metrics/test_detection.py
+++ b/test/metrics/test_detection.py
@@ -1,5 +1,5 @@
from contextlib import ExitStack as DoesNotRaise
-from test.utils import assert_almost_equal, mock_detections
+from test.test_utils import assert_almost_equal, mock_detections
from typing import Optional, Union
import numpy as np
diff --git a/test/utils.py b/test/test_utils.py
similarity index 100%
rename from test/utils.py
rename to test/test_utils.py
diff --git a/test/utils/__init__.py b/test/utils/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/test/utils/test_file.py b/test/utils/test_file.py
new file mode 100644
index 00000000..7a8dd37f
--- /dev/null
+++ b/test/utils/test_file.py
@@ -0,0 +1,64 @@
+import os
+from contextlib import ExitStack as DoesNotRaise
+from typing import List, Optional
+
+import pytest
+
+from supervision.utils.file import read_txt_file
+
+FILE_1_CONTENT = """Line 1
+Line 2
+Line 3
+"""
+
+FILE_2_CONTENT = """
+Line 2
+
+Line 4
+
+""" # noqa
+
+FILE_3_CONTENT = """
+Line 2
+
+Line 4
+
+"""
+
+
+@pytest.fixture(scope="module", autouse=True)
+def setup_and_teardown_files():
+ with open("file_1.txt", "w") as file:
+ file.write(FILE_1_CONTENT)
+ with open("file_2.txt", "w") as file:
+ file.write(FILE_2_CONTENT)
+ with open("file_3.txt", "w") as file:
+ file.write(FILE_3_CONTENT)
+
+ yield
+
+ os.remove("file_1.txt")
+ os.remove("file_2.txt")
+ os.remove("file_3.txt")
+
+
+@pytest.mark.parametrize(
+ "file_name, skip_empty, expected_result, exception",
+ [
+ ("file_1.txt", False, ["Line 1", "Line 2", "Line 3"], DoesNotRaise()),
+ ("file_2.txt", True, ["Line 2", "Line 4"], DoesNotRaise()),
+ ("file_2.txt", False, [" ", "Line 2", "", "Line 4", ""], DoesNotRaise()),
+ ("file_3.txt", True, ["Line 2", "Line 4"], DoesNotRaise()),
+ ("file_3.txt", False, ["", "Line 2", "", "Line 4", ""], DoesNotRaise()),
+ ("file_4.txt", True, None, pytest.raises(FileNotFoundError)),
+ ],
+)
+def test_read_txt_file(
+ file_name: str,
+ skip_empty: bool,
+ expected_result: Optional[List[str]],
+ exception: Exception,
+):
+ with exception:
+ result = read_txt_file(file_name, skip_empty)
+ assert result == expected_result