Merge branch 'develop' into add-ultralytics-SAM-support
This commit is contained in:
commit
526ddacd2f
|
|
@ -45,7 +45,7 @@ repos:
|
|||
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.5.5
|
||||
rev: v0.5.7
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
|
|
|||
|
|
@ -433,6 +433,27 @@ status: new
|
|||
|
||||
</div>
|
||||
|
||||
=== "Background Color"
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
image = ...
|
||||
detections = sv.Detections(...)
|
||||
|
||||
background_overlay_annotator = sv.BackgroundOverlayAnnotator()
|
||||
annotated_frame = background_overlay_annotator.annotate(
|
||||
scene=image.copy(),
|
||||
detections=detections
|
||||
)
|
||||
```
|
||||
|
||||
<div class="result" markdown>
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.annotators.core.BoxAnnotator">BoxAnnotator</a></h2>
|
||||
</div>
|
||||
|
|
@ -553,6 +574,12 @@ status: new
|
|||
|
||||
:::supervision.annotators.core.CropAnnotator
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.annotators.core.BackgroundOverlayAnnotator">BackgroundOverlayAnnotator</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.annotators.core.BackgroundOverlayAnnotator
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.annotators.core.ColorLookup">ColorLookup</a></h2>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2053,13 +2053,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "mike"
|
||||
version = "2.1.2"
|
||||
version = "2.1.3"
|
||||
description = "Manage multiple versions of your MkDocs-powered documentation"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "mike-2.1.2-py3-none-any.whl", hash = "sha256:d61d9b423ab412d634ca2bd520136d5114e3cc73f4bbd1aa6a0c6625c04918c0"},
|
||||
{file = "mike-2.1.2.tar.gz", hash = "sha256:d59cc8054c50f9c8a046cfd47f9b700cf9ff1b2b19f420bd8812ca6f94fa8bd3"},
|
||||
{file = "mike-2.1.3-py3-none-any.whl", hash = "sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a"},
|
||||
{file = "mike-2.1.3.tar.gz", hash = "sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -3205,62 +3205,64 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.1"
|
||||
version = "6.0.2"
|
||||
description = "YAML parser and emitter for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
|
||||
{file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
|
||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
|
||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
|
||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
|
||||
{file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
|
||||
{file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
|
||||
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3702,29 +3704,29 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.5.6"
|
||||
version = "0.5.7"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.5.6-py3-none-linux_armv6l.whl", hash = "sha256:a0ef5930799a05522985b9cec8290b185952f3fcd86c1772c3bdbd732667fdcd"},
|
||||
{file = "ruff-0.5.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b652dc14f6ef5d1552821e006f747802cc32d98d5509349e168f6bf0ee9f8f42"},
|
||||
{file = "ruff-0.5.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:80521b88d26a45e871f31e4b88938fd87db7011bb961d8afd2664982dfc3641a"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9bc8f328a9f1309ae80e4d392836e7dbc77303b38ed4a7112699e63d3b066ab"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d394940f61f7720ad371ddedf14722ee1d6250fd8d020f5ea5a86e7be217daf"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111a99cdb02f69ddb2571e2756e017a1496c2c3a2aeefe7b988ddab38b416d36"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e395daba77a79f6dc0d07311f94cc0560375ca20c06f354c7c99af3bf4560c5d"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c476acb43c3c51e3c614a2e878ee1589655fa02dab19fe2db0423a06d6a5b1b6"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2ff8003f5252fd68425fd53d27c1f08b201d7ed714bb31a55c9ac1d4c13e2eb"},
|
||||
{file = "ruff-0.5.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c94e084ba3eaa80c2172918c2ca2eb2230c3f15925f4ed8b6297260c6ef179ad"},
|
||||
{file = "ruff-0.5.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1f77c1c3aa0669fb230b06fb24ffa3e879391a3ba3f15e3d633a752da5a3e670"},
|
||||
{file = "ruff-0.5.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f908148c93c02873210a52cad75a6eda856b2cbb72250370ce3afef6fb99b1ed"},
|
||||
{file = "ruff-0.5.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:563a7ae61ad284187d3071d9041c08019975693ff655438d8d4be26e492760bd"},
|
||||
{file = "ruff-0.5.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:94fe60869bfbf0521e04fd62b74cbca21cbc5beb67cbb75ab33fe8c174f54414"},
|
||||
{file = "ruff-0.5.6-py3-none-win32.whl", hash = "sha256:e6a584c1de6f8591c2570e171cc7ce482bb983d49c70ddf014393cd39e9dfaed"},
|
||||
{file = "ruff-0.5.6-py3-none-win_amd64.whl", hash = "sha256:d7fe7dccb1a89dc66785d7aa0ac283b2269712d8ed19c63af908fdccca5ccc1a"},
|
||||
{file = "ruff-0.5.6-py3-none-win_arm64.whl", hash = "sha256:57c6c0dd997b31b536bff49b9eee5ed3194d60605a4427f735eeb1f9c1b8d264"},
|
||||
{file = "ruff-0.5.6.tar.gz", hash = "sha256:07c9e3c2a8e1fe377dd460371c3462671a728c981c3205a5217291422209f642"},
|
||||
{file = "ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a"},
|
||||
{file = "ruff-0.5.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be"},
|
||||
{file = "ruff-0.5.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb"},
|
||||
{file = "ruff-0.5.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e"},
|
||||
{file = "ruff-0.5.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499"},
|
||||
{file = "ruff-0.5.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e"},
|
||||
{file = "ruff-0.5.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5"},
|
||||
{file = "ruff-0.5.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e"},
|
||||
{file = "ruff-0.5.7-py3-none-win32.whl", hash = "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a"},
|
||||
{file = "ruff-0.5.7-py3-none-win_amd64.whl", hash = "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3"},
|
||||
{file = "ruff-0.5.7-py3-none-win_arm64.whl", hash = "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4"},
|
||||
{file = "ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3989,17 +3991,17 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "tox"
|
||||
version = "4.16.0"
|
||||
version = "4.18.0"
|
||||
description = "tox is a generic virtualenv management and test command line tool"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tox-4.16.0-py3-none-any.whl", hash = "sha256:61e101061b977b46cf00093d4319438055290ad0009f84497a07bf2d2d7a06d0"},
|
||||
{file = "tox-4.16.0.tar.gz", hash = "sha256:43499656f9949edb681c0f907f86fbfee98677af9919d8b11ae5ad77cb800748"},
|
||||
{file = "tox-4.18.0-py3-none-any.whl", hash = "sha256:0a457400cf70615dc0627eb70d293e80cd95d8ce174bb40ac011011f0c03a249"},
|
||||
{file = "tox-4.18.0.tar.gz", hash = "sha256:5dfa1cab9f146becd6e351333a82f9e0ade374451630ba65ee54584624c27b58"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cachetools = ">=5.3.3"
|
||||
cachetools = ">=5.4"
|
||||
chardet = ">=5.2"
|
||||
colorama = ">=0.4.6"
|
||||
filelock = ">=3.15.4"
|
||||
|
|
@ -4011,8 +4013,8 @@ tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
|||
virtualenv = ">=20.26.3"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2024.5.6)", "sphinx (>=7.3.7)", "sphinx-argparse-cli (>=1.16)", "sphinx-autodoc-typehints (>=2.2.2)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.11)"]
|
||||
testing = ["build[virtualenv] (>=1.2.1)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.2)", "devpi-process (>=1)", "diff-cover (>=9.1)", "distlib (>=0.3.8)", "flaky (>=3.8.1)", "hatch-vcs (>=0.4)", "hatchling (>=1.25)", "psutil (>=6)", "pytest (>=8.2.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-xdist (>=3.6.1)", "re-assert (>=1.1)", "setuptools (>=70.2)", "time-machine (>=2.14.2)", "wheel (>=0.43)"]
|
||||
docs = ["furo (>=2024.7.18)", "sphinx (>=7.4.7)", "sphinx-argparse-cli (>=1.16)", "sphinx-autodoc-typehints (>=2.2.3)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.11)"]
|
||||
testing = ["build[virtualenv] (>=1.2.1)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.2)", "devpi-process (>=1)", "diff-cover (>=9.1.1)", "distlib (>=0.3.8)", "flaky (>=3.8.1)", "hatch-vcs (>=0.4)", "hatchling (>=1.25)", "psutil (>=6)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-xdist (>=3.6.1)", "re-assert (>=1.1)", "setuptools (>=70.3)", "time-machine (>=2.14.2)", "wheel (>=0.43)"]
|
||||
|
||||
[[package]]
|
||||
name = "tqdm"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ except importlib_metadata.PackageNotFoundError:
|
|||
__version__ = "development"
|
||||
|
||||
from supervision.annotators.core import (
|
||||
BackgroundOverlayAnnotator,
|
||||
BlurAnnotator,
|
||||
BoundingBoxAnnotator,
|
||||
BoxAnnotator,
|
||||
|
|
|
|||
|
|
@ -2283,3 +2283,84 @@ class CropAnnotator(BaseAnnotator):
|
|||
)
|
||||
elif position == Position.BOTTOM_RIGHT:
|
||||
return (anchor_x, anchor_y), (anchor_x + width, anchor_y + height)
|
||||
|
||||
|
||||
class BackgroundOverlayAnnotator(BaseAnnotator):
|
||||
"""
|
||||
A class for drawing a colored overlay on the background of an image outside
|
||||
the region of detections.
|
||||
|
||||
If masks are provided, the background is colored outside the masks.
|
||||
If masks are not provided, the background is colored outside the bounding boxes.
|
||||
|
||||
You can use the `force_box` parameter to force the annotator to use bounding boxes.
|
||||
|
||||
!!! warning
|
||||
|
||||
This annotator uses `sv.Detections.mask`.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
color: Color = Color.BLACK,
|
||||
opacity: float = 0.5,
|
||||
force_box: bool = False,
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
color (Color): The color to use for annotating detections.
|
||||
opacity (float): Opacity of the overlay mask. Must be between `0` and `1`.
|
||||
force_box (bool): If `True`, forces the annotator to use bounding boxes when
|
||||
masks are provided in the supplied sv.Detections.
|
||||
"""
|
||||
self.color: Color = color
|
||||
self.opacity = opacity
|
||||
self.force_box = force_box
|
||||
|
||||
@ensure_cv2_image_for_annotation
|
||||
def annotate(self, scene: ImageType, detections: Detections) -> ImageType:
|
||||
"""
|
||||
Applies a colored overlay to the scene outside of the detected regions.
|
||||
|
||||
Args:
|
||||
scene (ImageType): The image where masks will be drawn.
|
||||
`ImageType` is a flexible type, accepting either `numpy.ndarray`
|
||||
or `PIL.Image.Image`.
|
||||
detections (Detections): Object detections to annotate.
|
||||
|
||||
Returns:
|
||||
The annotated image, matching the type of `scene` (`numpy.ndarray`
|
||||
or `PIL.Image.Image`)
|
||||
|
||||
Example:
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
image = ...
|
||||
detections = sv.Detections(...)
|
||||
|
||||
background_overlay_annotator = sv.BackgroundOverlayAnnotator()
|
||||
annotated_frame = background_overlay_annotator.annotate(
|
||||
scene=image.copy(),
|
||||
detections=detections
|
||||
)
|
||||
```
|
||||
|
||||

|
||||
"""
|
||||
colored_mask = np.full_like(scene, self.color.as_bgr(), dtype=np.uint8)
|
||||
|
||||
cv2.addWeighted(
|
||||
scene, 1 - self.opacity, colored_mask, self.opacity, 0, dst=colored_mask
|
||||
)
|
||||
|
||||
if detections.mask is None or self.force_box:
|
||||
for x1, y1, x2, y2 in detections.xyxy.astype(int):
|
||||
colored_mask[y1:y2, x1:x2] = scene[y1:y2, x1:x2]
|
||||
else:
|
||||
for mask in detections.mask:
|
||||
colored_mask[mask] = scene[mask]
|
||||
|
||||
np.copyto(scene, colored_mask)
|
||||
return scene
|
||||
|
|
|
|||
|
|
@ -18,13 +18,17 @@ from supervision.detection.overlap_filter import (
|
|||
box_non_max_suppression,
|
||||
mask_non_max_suppression,
|
||||
)
|
||||
from supervision.detection.tools.transformers import (
|
||||
process_transformers_detection_result,
|
||||
process_transformers_v4_segmentation_result,
|
||||
process_transformers_v5_segmentation_result,
|
||||
)
|
||||
from supervision.detection.utils import (
|
||||
box_iou_batch,
|
||||
calculate_masks_centroids,
|
||||
extract_ultralytics_masks,
|
||||
get_data_item,
|
||||
is_data_equal,
|
||||
mask_to_xyxy,
|
||||
merge_data,
|
||||
process_roboflow_result,
|
||||
xywh_to_xyxy,
|
||||
|
|
@ -244,10 +248,6 @@ class Detections:
|
|||
results = model(image)[0]
|
||||
detections = sv.Detections.from_ultralytics(results)
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
Class names values can be accessed using `detections["class_name"]`.
|
||||
""" # noqa: E501 // docs
|
||||
|
||||
if hasattr(ultralytics_results, "obb") and ultralytics_results.obb is not None:
|
||||
|
|
@ -446,15 +446,19 @@ class Detections:
|
|||
cls, transformers_results: dict, id2label: Optional[Dict[int, str]] = None
|
||||
) -> Detections:
|
||||
"""
|
||||
Creates a Detections instance from object detection or segmentation
|
||||
Creates a Detections instance from object detection or panoptic, semantic
|
||||
and instance segmentation
|
||||
[Transformer](https://github.com/huggingface/transformers) inference result.
|
||||
|
||||
Args:
|
||||
transformers_results (dict): The output of Transformers model inference. A
|
||||
dictionary containing the `scores`, `labels`, `boxes` and `masks` keys.
|
||||
transformers_results (Union[dict, torch.Tensor]): Inference results from
|
||||
your Transformers model. This can be either a dictionary containing
|
||||
valuable outputs like `scores`, `labels`, `boxes`, `masks`,
|
||||
`segments_info`, and `segmentation`, or a `torch.Tensor` holding a
|
||||
segmentation map where values represent class IDs.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to
|
||||
class names. If provided, the resulting Detections object will contain
|
||||
`class_name` data field with the class names.
|
||||
labels, typically part of the `transformers` model configuration. If
|
||||
provided, the resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
Detections: A new Detections object.
|
||||
|
|
@ -485,36 +489,28 @@ class Detections:
|
|||
id2label=model.config.id2label
|
||||
)
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
Class names values can be accessed using `detections["class_name"]`.
|
||||
""" # noqa: E501 // docs
|
||||
|
||||
class_ids = transformers_results["labels"].cpu().detach().numpy().astype(int)
|
||||
data = {}
|
||||
if id2label is not None:
|
||||
class_names = np.array([id2label[class_id] for class_id in class_ids])
|
||||
data[CLASS_NAME_DATA_FIELD] = class_names
|
||||
if (
|
||||
transformers_results.__class__.__name__ == "Tensor"
|
||||
or "segmentation" in transformers_results
|
||||
):
|
||||
return cls(
|
||||
**process_transformers_v5_segmentation_result(
|
||||
transformers_results, id2label
|
||||
)
|
||||
)
|
||||
|
||||
if "masks" in transformers_results or "png_string" in transformers_results:
|
||||
return cls(
|
||||
**process_transformers_v4_segmentation_result(
|
||||
transformers_results, id2label
|
||||
)
|
||||
)
|
||||
|
||||
if "boxes" in transformers_results:
|
||||
return cls(
|
||||
xyxy=transformers_results["boxes"].cpu().detach().numpy(),
|
||||
confidence=transformers_results["scores"].cpu().detach().numpy(),
|
||||
class_id=class_ids,
|
||||
data=data,
|
||||
)
|
||||
elif "masks" in transformers_results:
|
||||
masks = transformers_results["masks"].cpu().detach().numpy().astype(bool)
|
||||
return cls(
|
||||
xyxy=mask_to_xyxy(masks),
|
||||
mask=masks,
|
||||
confidence=transformers_results["scores"].cpu().detach().numpy(),
|
||||
class_id=class_ids,
|
||||
data=data,
|
||||
)
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"Only object detection and semantic segmentation results are supported."
|
||||
**process_transformers_detection_result(transformers_results, id2label)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
@ -591,10 +587,6 @@ class Detections:
|
|||
result = model.infer(image)[0]
|
||||
detections = sv.Detections.from_inference(result)
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
Class names values can be accessed using `detections["class_name"]`.
|
||||
"""
|
||||
with suppress(AttributeError):
|
||||
roboflow_result = roboflow_result.dict(exclude_none=True, by_alias=True)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import List, Union
|
||||
|
||||
|
|
@ -248,16 +250,21 @@ class OverlapFilter(Enum):
|
|||
NON_MAX_SUPPRESSION = "non_max_suppression"
|
||||
NON_MAX_MERGE = "non_max_merge"
|
||||
|
||||
@classmethod
|
||||
def list(cls):
|
||||
return list(map(lambda c: c.value, cls))
|
||||
|
||||
def validate_overlap_filter(
|
||||
strategy: Union[OverlapFilter, str],
|
||||
) -> OverlapFilter:
|
||||
if isinstance(strategy, str):
|
||||
try:
|
||||
strategy = OverlapFilter(strategy.lower())
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
f"Invalid strategy value: {strategy}. Must be one of "
|
||||
f"{[e.value for e in OverlapFilter]}"
|
||||
)
|
||||
return strategy
|
||||
@classmethod
|
||||
def from_value(cls, value: Union[OverlapFilter, str]) -> OverlapFilter:
|
||||
if isinstance(value, cls):
|
||||
return value
|
||||
if isinstance(value, str):
|
||||
value = value.lower()
|
||||
try:
|
||||
return cls(value)
|
||||
except ValueError:
|
||||
raise ValueError(f"Invalid value: {value}. Must be one of {cls.list()}")
|
||||
raise ValueError(
|
||||
f"Invalid value type: {type(value)}. Must be an instance of "
|
||||
f"{cls.__name__} or str."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@ import numpy as np
|
|||
|
||||
from supervision.config import ORIENTED_BOX_COORDINATES
|
||||
from supervision.detection.core import Detections
|
||||
from supervision.detection.overlap_filter import OverlapFilter, validate_overlap_filter
|
||||
from supervision.detection.overlap_filter import OverlapFilter
|
||||
from supervision.detection.utils import move_boxes, move_masks, move_oriented_boxes
|
||||
from supervision.utils.image import crop_image
|
||||
from supervision.utils.internal import SupervisionWarnings
|
||||
from supervision.utils.internal import (
|
||||
SupervisionWarnings,
|
||||
deprecated_parameter,
|
||||
warn_deprecated,
|
||||
)
|
||||
|
||||
|
||||
def move_detections(
|
||||
|
|
@ -54,11 +58,16 @@ class InferenceSlicer:
|
|||
slice, and then merging the detections.
|
||||
|
||||
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)`.
|
||||
overlap_filter_strategy (Union[OverlapFilter, str]): Strategy for
|
||||
slice_wh (Tuple[int, int]): Dimensions of each slice measured in pixels. The
|
||||
tuple should be in the format `(width, height)`.
|
||||
overlap_ratio_wh (Optional[Tuple[float, float]]): A tuple representing the
|
||||
desired overlap ratio for width and height between consecutive slices.
|
||||
Each value should be in the range [0, 1), where 0 means no overlap and
|
||||
a value close to 1 means high overlap.
|
||||
overlap_wh (Optional[Tuple[int, int]]): A tuple representing the desired
|
||||
overlap for width and height between consecutive slices measured in pixels.
|
||||
Each value should be greater than or equal to 0.
|
||||
overlap_filter (Union[OverlapFilter, str]): Strategy for
|
||||
filtering or merging overlapping detections in slices.
|
||||
iou_threshold (float): Intersection over Union (IoU) threshold
|
||||
used when filtering by overlap.
|
||||
|
|
@ -73,23 +82,37 @@ class InferenceSlicer:
|
|||
not a multiple of the slice's width or height minus the overlap.
|
||||
"""
|
||||
|
||||
@deprecated_parameter(
|
||||
old_parameter="overlap_filter_strategy",
|
||||
new_parameter="overlap_filter",
|
||||
map_function=lambda x: x,
|
||||
warning_message="`{old_parameter}` in `{function_name}` is deprecated and will "
|
||||
"be removed in `supervision-0.27.0`. Use '{new_parameter}' "
|
||||
"instead.",
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[np.ndarray], Detections],
|
||||
slice_wh: Tuple[int, int] = (320, 320),
|
||||
overlap_ratio_wh: Tuple[float, float] = (0.2, 0.2),
|
||||
overlap_filter_strategy: Union[
|
||||
OverlapFilter, str
|
||||
] = OverlapFilter.NON_MAX_SUPPRESSION,
|
||||
overlap_ratio_wh: Optional[Tuple[float, float]] = (0.2, 0.2),
|
||||
overlap_wh: Optional[Tuple[int, int]] = None,
|
||||
overlap_filter: Union[OverlapFilter, str] = OverlapFilter.NON_MAX_SUPPRESSION,
|
||||
iou_threshold: float = 0.5,
|
||||
thread_workers: int = 1,
|
||||
):
|
||||
overlap_filter_strategy = validate_overlap_filter(overlap_filter_strategy)
|
||||
if overlap_ratio_wh is not None:
|
||||
warn_deprecated(
|
||||
"`overlap_ratio_wh` in `InferenceSlicer.__init__` is deprecated and "
|
||||
"will be removed in `supervision-0.27.0`. Use `overlap_wh` instead."
|
||||
)
|
||||
|
||||
self._validate_overlap(overlap_ratio_wh, overlap_wh)
|
||||
self.overlap_ratio_wh = overlap_ratio_wh
|
||||
self.overlap_wh = overlap_wh
|
||||
|
||||
self.slice_wh = slice_wh
|
||||
self.overlap_ratio_wh = overlap_ratio_wh
|
||||
self.iou_threshold = iou_threshold
|
||||
self.overlap_filter_strategy = overlap_filter_strategy
|
||||
self.overlap_filter = OverlapFilter.from_value(overlap_filter)
|
||||
self.callback = callback
|
||||
self.thread_workers = thread_workers
|
||||
|
||||
|
|
@ -134,6 +157,7 @@ class InferenceSlicer:
|
|||
resolution_wh=resolution_wh,
|
||||
slice_wh=self.slice_wh,
|
||||
overlap_ratio_wh=self.overlap_ratio_wh,
|
||||
overlap_wh=self.overlap_wh,
|
||||
)
|
||||
|
||||
with ThreadPoolExecutor(max_workers=self.thread_workers) as executor:
|
||||
|
|
@ -144,15 +168,15 @@ class InferenceSlicer:
|
|||
detections_list.append(future.result())
|
||||
|
||||
merged = Detections.merge(detections_list=detections_list)
|
||||
if self.overlap_filter_strategy == OverlapFilter.NONE:
|
||||
if self.overlap_filter == OverlapFilter.NONE:
|
||||
return merged
|
||||
elif self.overlap_filter_strategy == OverlapFilter.NON_MAX_SUPPRESSION:
|
||||
elif self.overlap_filter == OverlapFilter.NON_MAX_SUPPRESSION:
|
||||
return merged.with_nms(threshold=self.iou_threshold)
|
||||
elif self.overlap_filter_strategy == OverlapFilter.NON_MAX_MERGE:
|
||||
elif self.overlap_filter == OverlapFilter.NON_MAX_MERGE:
|
||||
return merged.with_nmm(threshold=self.iou_threshold)
|
||||
else:
|
||||
warnings.warn(
|
||||
f"Invalid overlap filter strategy: {self.overlap_filter_strategy}",
|
||||
f"Invalid overlap filter strategy: {self.overlap_filter}",
|
||||
category=SupervisionWarnings,
|
||||
)
|
||||
return merged
|
||||
|
|
@ -182,7 +206,8 @@ class InferenceSlicer:
|
|||
def _generate_offset(
|
||||
resolution_wh: Tuple[int, int],
|
||||
slice_wh: Tuple[int, int],
|
||||
overlap_ratio_wh: Tuple[float, float],
|
||||
overlap_ratio_wh: Optional[Tuple[float, float]],
|
||||
overlap_wh: Optional[Tuple[int, int]],
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
Generate offset coordinates for slicing an image based on the given resolution,
|
||||
|
|
@ -191,12 +216,15 @@ class InferenceSlicer:
|
|||
Args:
|
||||
resolution_wh (Tuple[int, int]): A tuple representing the width and height
|
||||
of the image to be sliced.
|
||||
slice_wh (Tuple[int, int]): A tuple representing the desired width and
|
||||
height of each slice.
|
||||
overlap_ratio_wh (Tuple[float, float]): A tuple representing the desired
|
||||
overlap ratio for width and height between consecutive slices. Each
|
||||
value should be in the range [0, 1), where 0 means no overlap and a
|
||||
value close to 1 means high overlap.
|
||||
slice_wh (Tuple[int, int]): Dimensions of each slice measured in pixels. The
|
||||
tuple should be in the format `(width, height)`.
|
||||
overlap_ratio_wh (Optional[Tuple[float, float]]): A tuple representing the
|
||||
desired overlap ratio for width and height between consecutive slices.
|
||||
Each value should be in the range [0, 1), where 0 means no overlap and
|
||||
a value close to 1 means high overlap.
|
||||
overlap_wh (Optional[Tuple[int, int]]): A tuple representing the desired
|
||||
overlap for width and height between consecutive slices measured in
|
||||
pixels. Each value should be greater than or equal to 0.
|
||||
|
||||
Returns:
|
||||
np.ndarray: An array of shape `(n, 4)` containing coordinates for each
|
||||
|
|
@ -211,10 +239,19 @@ class InferenceSlicer:
|
|||
"""
|
||||
slice_width, slice_height = slice_wh
|
||||
image_width, image_height = resolution_wh
|
||||
overlap_ratio_width, overlap_ratio_height = overlap_ratio_wh
|
||||
overlap_width = (
|
||||
overlap_wh[0]
|
||||
if overlap_wh is not None
|
||||
else int(overlap_ratio_wh[0] * slice_width)
|
||||
)
|
||||
overlap_height = (
|
||||
overlap_wh[1]
|
||||
if overlap_wh is not None
|
||||
else int(overlap_ratio_wh[1] * slice_height)
|
||||
)
|
||||
|
||||
width_stride = slice_width - int(overlap_ratio_width * slice_width)
|
||||
height_stride = slice_height - int(overlap_ratio_height * slice_height)
|
||||
width_stride = slice_width - overlap_width
|
||||
height_stride = slice_height - overlap_height
|
||||
|
||||
ws = np.arange(0, image_width, width_stride)
|
||||
hs = np.arange(0, image_height, height_stride)
|
||||
|
|
@ -226,3 +263,32 @@ class InferenceSlicer:
|
|||
offsets = np.stack([xmin, ymin, xmax, ymax], axis=-1).reshape(-1, 4)
|
||||
|
||||
return offsets
|
||||
|
||||
@staticmethod
|
||||
def _validate_overlap(
|
||||
overlap_ratio_wh: Optional[Tuple[float, float]],
|
||||
overlap_wh: Optional[Tuple[int, int]],
|
||||
) -> None:
|
||||
if overlap_ratio_wh is not None and overlap_wh is not None:
|
||||
raise ValueError(
|
||||
"Both `overlap_ratio_wh` and `overlap_wh` cannot be provided. "
|
||||
"Please provide only one of them."
|
||||
)
|
||||
if overlap_ratio_wh is None and overlap_wh is None:
|
||||
raise ValueError(
|
||||
"Either `overlap_ratio_wh` or `overlap_wh` must be provided. "
|
||||
"Please provide one of them."
|
||||
)
|
||||
|
||||
if overlap_ratio_wh is not None:
|
||||
if not (0 <= overlap_ratio_wh[0] < 1 and 0 <= overlap_ratio_wh[1] < 1):
|
||||
raise ValueError(
|
||||
"Overlap ratios must be in the range [0, 1). "
|
||||
f"Received: {overlap_ratio_wh}"
|
||||
)
|
||||
if overlap_wh is not None:
|
||||
if not (overlap_wh[0] >= 0 and overlap_wh[1] >= 0):
|
||||
raise ValueError(
|
||||
"Overlap values must be greater than or equal to 0. "
|
||||
f"Received: {overlap_wh}"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,247 @@
|
|||
import io
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
from supervision.config import CLASS_NAME_DATA_FIELD
|
||||
from supervision.detection.utils import mask_to_xyxy
|
||||
|
||||
|
||||
def process_transformers_detection_result(
|
||||
detection_result: dict, id2label: Optional[Dict[int, str]]
|
||||
) -> dict:
|
||||
"""
|
||||
Process the result of Transformers object detection functions such as
|
||||
`post_process` (v4) and `post_process_detection` (v5).
|
||||
|
||||
Args:
|
||||
detection_result (dict): Dictionary containing detection results with keys
|
||||
'boxes', 'labels', and 'scores'.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
dict: Processed detection result including bounding boxes, confidence scores,
|
||||
class IDs, and data.
|
||||
"""
|
||||
class_ids = detection_result["labels"].cpu().detach().numpy().astype(int)
|
||||
data = append_class_names_to_data(class_ids, id2label, {})
|
||||
|
||||
return dict(
|
||||
xyxy=detection_result["boxes"].cpu().detach().numpy(),
|
||||
confidence=detection_result["scores"].cpu().detach().numpy(),
|
||||
class_id=class_ids,
|
||||
data=data,
|
||||
)
|
||||
|
||||
|
||||
def process_transformers_v4_segmentation_result(
|
||||
segmentation_result: dict, id2label: Optional[Dict[int, str]]
|
||||
) -> dict:
|
||||
"""
|
||||
Process the result of Transformers segmentation functions such as
|
||||
`post_process_panoptic`, `post_process_segmentation`, and `post_process_instance`
|
||||
(v4).
|
||||
|
||||
Args:
|
||||
segmentation_result (dict): Dictionary containing segmentation results with keys
|
||||
'masks', 'labels', and 'scores'.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
dict: Processed segmentation result including bounding boxes, masks, confidence
|
||||
scores, class IDs, and data.
|
||||
"""
|
||||
if "png_string" in segmentation_result:
|
||||
return process_transformers_v4_panoptic_segmentation_result(
|
||||
segmentation_result, id2label
|
||||
)
|
||||
else:
|
||||
boxes = None
|
||||
if "boxes" in segmentation_result:
|
||||
boxes = segmentation_result["boxes"].cpu().detach().numpy()
|
||||
masks = segmentation_result["masks"].cpu().detach().numpy().astype(bool)
|
||||
class_ids = segmentation_result["labels"].cpu().detach().numpy().astype(int)
|
||||
|
||||
return dict(
|
||||
xyxy=boxes if boxes is not None else mask_to_xyxy(masks),
|
||||
mask=np.squeeze(masks, axis=1) if boxes is not None else masks,
|
||||
confidence=segmentation_result["scores"].cpu().detach().numpy(),
|
||||
class_id=class_ids,
|
||||
data=append_class_names_to_data(class_ids, id2label, {}),
|
||||
)
|
||||
|
||||
|
||||
def process_transformers_v5_segmentation_result(
|
||||
segmentation_result: dict, id2label: Optional[Dict[int, str]]
|
||||
) -> dict:
|
||||
"""
|
||||
Process the result of Transformers segmentation functions such as
|
||||
`post_process_semantic_segmentation`, `post_process_instance_segmentation`, and
|
||||
`post_process_panoptic_segmentation` (v5).
|
||||
|
||||
Args:
|
||||
segmentation_result (Union[dict, np.ndarray]): Either a dictionary containing
|
||||
segmentation results or an ndarray representing a segmentation map.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
dict: Processed segmentation result including bounding boxes, masks, confidence
|
||||
scores, class IDs, and data.
|
||||
"""
|
||||
if segmentation_result.__class__.__name__ == "Tensor":
|
||||
segmentation_array = segmentation_result.cpu().detach().numpy()
|
||||
return process_transformers_v5_panoptic_segmentation_result(
|
||||
segmentation_array, id2label
|
||||
)
|
||||
|
||||
return process_transformers_v5_semantic_or_instance_segmentation_result(
|
||||
segmentation_result, id2label
|
||||
)
|
||||
|
||||
|
||||
def process_transformers_v5_semantic_or_instance_segmentation_result(
|
||||
segmentation_result: dict, id2label: Optional[Dict[int, str]]
|
||||
) -> dict:
|
||||
"""
|
||||
Process the result of Transformers segmentation functions such as
|
||||
`post_process_semantic_segmentation` and `post_process_instance_segmentation` (v5).
|
||||
|
||||
Args:
|
||||
segmentation_result (dict): Dictionary containing segmentation results with keys
|
||||
`segments_info` and `segmentation`.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
dict: Processed segmentation result including bounding boxes, masks, confidence
|
||||
scores, class IDs, and data.
|
||||
"""
|
||||
segments_info = segmentation_result["segments_info"]
|
||||
scores = np.array([segment["score"] for segment in segments_info])
|
||||
class_ids = np.array([segment["label_id"] for segment in segments_info])
|
||||
segmentation_array = segmentation_result["segmentation"].cpu().detach().numpy()
|
||||
masks = np.array(
|
||||
[segmentation_array == segment["id"] for segment in segments_info]
|
||||
).astype(bool)
|
||||
data = append_class_names_to_data(class_ids, id2label, {})
|
||||
|
||||
return dict(
|
||||
xyxy=mask_to_xyxy(masks),
|
||||
mask=masks,
|
||||
confidence=scores,
|
||||
class_id=class_ids,
|
||||
data=data,
|
||||
)
|
||||
|
||||
|
||||
def process_transformers_v4_panoptic_segmentation_result(
|
||||
segmentation_result: dict, id2label: Optional[Dict[int, str]]
|
||||
) -> dict:
|
||||
"""
|
||||
Process the result of the Transformers function `post_process_panoptic` (v4).
|
||||
|
||||
Args:
|
||||
segmentation_result (dict): Dictionary containing segmentation results with keys
|
||||
such as 'png_string' and 'segments_info'.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
dict: Processed segmentation result including bounding boxes, masks,
|
||||
class IDs, and data.
|
||||
"""
|
||||
segments_info = segmentation_result["segments_info"]
|
||||
png_string = segmentation_result["png_string"]
|
||||
class_ids = np.array([segment["category_id"] for segment in segments_info])
|
||||
segmentation_array = png_string_to_segmentation_array(png_string=png_string)
|
||||
masks = np.array(
|
||||
[segmentation_array == segment["id"] for segment in segments_info]
|
||||
).astype(bool)
|
||||
data = append_class_names_to_data(class_ids, id2label, {})
|
||||
|
||||
return dict(
|
||||
xyxy=mask_to_xyxy(masks),
|
||||
mask=masks,
|
||||
class_id=class_ids,
|
||||
data=data,
|
||||
)
|
||||
|
||||
|
||||
def process_transformers_v5_panoptic_segmentation_result(
|
||||
segmentation_array: np.ndarray, id2label: Optional[Dict[int, str]]
|
||||
) -> dict:
|
||||
"""
|
||||
Process the result of the Transformers function
|
||||
`post_process_panoptic_segmentation` (v5).
|
||||
|
||||
Args:
|
||||
segmentation_array (np.ndarray): Segmentation array.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
|
||||
Returns:
|
||||
dict: Processed segmentation result including bounding boxes, masks,
|
||||
class IDs, and data.
|
||||
"""
|
||||
class_ids = np.unique(segmentation_array)
|
||||
masks = np.stack(
|
||||
[segmentation_array == class_id for class_id in class_ids], axis=0
|
||||
).astype(bool)
|
||||
data = append_class_names_to_data(class_ids, id2label, {})
|
||||
return dict(xyxy=mask_to_xyxy(masks), mask=masks, class_id=class_ids, data=data)
|
||||
|
||||
|
||||
def png_string_to_segmentation_array(png_string: bytes) -> np.ndarray:
|
||||
"""
|
||||
Convert a PNG byte string to a label mask array.
|
||||
|
||||
Args:
|
||||
png_string (bytes): A byte string representing the PNG image.
|
||||
|
||||
Returns:
|
||||
np.ndarray: A label mask array with shape (H, W), where H and W
|
||||
are the height and width of the image. Each unique value in the array
|
||||
represents a different object or category.
|
||||
"""
|
||||
image = Image.open(io.BytesIO(png_string))
|
||||
mask = np.array(image, dtype=np.uint8)
|
||||
return mask[:, :, 0]
|
||||
|
||||
|
||||
def append_class_names_to_data(
|
||||
class_ids: np.ndarray,
|
||||
id2label: Optional[Dict[int, str]],
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Helper function to create or append to a data dictionary with class names if
|
||||
available.
|
||||
|
||||
Args:
|
||||
class_ids (np.ndarray): Array of class IDs.
|
||||
id2label (Optional[Dict[int, str]]): A dictionary mapping class IDs to labels,
|
||||
typically part of the `transformers` model configuration. If provided, the
|
||||
resulting dictionary will include class names.
|
||||
data (Optional[Dict[str, Any]]): An existing data dictionary to append to.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Dictionary containing class names if id2label is provided.
|
||||
"""
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
if id2label is not None:
|
||||
class_names = np.array([id2label[class_id] for class_id in class_ids])
|
||||
data[CLASS_NAME_DATA_FIELD] = class_names
|
||||
|
||||
return data
|
||||
|
|
@ -194,7 +194,7 @@ class VertexLabelAnnotator:
|
|||
def __init__(
|
||||
self,
|
||||
color: Union[Color, List[Color]] = Color.ROBOFLOW,
|
||||
text_color: Color = Color.WHITE,
|
||||
text_color: Union[Color, List[Color]] = Color.WHITE,
|
||||
text_scale: float = 0.5,
|
||||
text_thickness: int = 1,
|
||||
text_padding: int = 10,
|
||||
|
|
@ -205,7 +205,9 @@ class VertexLabelAnnotator:
|
|||
color (Union[Color, List[Color]], optional): The color to use for each
|
||||
keypoint label. If a list is provided, the colors will be used in order
|
||||
for each keypoint.
|
||||
text_color (Color, optional): The color to use for the labels.
|
||||
text_color (Union[Color, List[Color]], optional): The color to use
|
||||
for the labels. If a list is provided, the colors will be used in order
|
||||
for each keypoint.
|
||||
text_scale (float, optional): The scale of the text.
|
||||
text_thickness (int, optional): The thickness of the text.
|
||||
text_padding (int, optional): The padding around the text.
|
||||
|
|
@ -214,7 +216,7 @@ class VertexLabelAnnotator:
|
|||
"""
|
||||
self.border_radius: int = border_radius
|
||||
self.color: Union[Color, List[Color]] = color
|
||||
self.text_color: Color = text_color
|
||||
self.text_color: Union[Color, List[Color]] = text_color
|
||||
self.text_scale: float = text_scale
|
||||
self.text_thickness: int = text_thickness
|
||||
self.text_padding: int = text_padding
|
||||
|
|
@ -321,12 +323,19 @@ class VertexLabelAnnotator:
|
|||
skeletons_count=skeletons_count,
|
||||
)
|
||||
|
||||
text_colors = self.preprocess_and_validate_colors(
|
||||
colors=self.text_color,
|
||||
points_count=points_count,
|
||||
skeletons_count=skeletons_count,
|
||||
)
|
||||
|
||||
labels = self.preprocess_and_validate_labels(
|
||||
labels=labels, points_count=points_count, skeletons_count=skeletons_count
|
||||
)
|
||||
|
||||
anchors = anchors[mask]
|
||||
colors = colors[mask]
|
||||
text_colors = text_colors[mask]
|
||||
labels = labels[mask]
|
||||
|
||||
xyxy = np.array(
|
||||
|
|
@ -344,7 +353,9 @@ class VertexLabelAnnotator:
|
|||
|
||||
xyxy_padded = pad_boxes(xyxy=xyxy, px=self.text_padding)
|
||||
|
||||
for text, color, box, box_padded in zip(labels, colors, xyxy, xyxy_padded):
|
||||
for text, color, text_color, box, box_padded in zip(
|
||||
labels, colors, text_colors, xyxy, xyxy_padded
|
||||
):
|
||||
draw_rounded_rectangle(
|
||||
scene=scene,
|
||||
rect=Rect.from_xyxy(box_padded),
|
||||
|
|
@ -357,7 +368,7 @@ class VertexLabelAnnotator:
|
|||
org=(box[0], box[3]),
|
||||
fontFace=font,
|
||||
fontScale=self.text_scale,
|
||||
color=self.text_color.as_rgb(),
|
||||
color=text_color.as_bgr(),
|
||||
thickness=self.text_thickness,
|
||||
lineType=cv2.LINE_AA,
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue