Merge pull request #1742 from roboflow/develop
`supervision-0.26.0` release
This commit is contained in:
commit
d8de58d7f3
|
|
@ -0,0 +1,4 @@
|
|||
# These owners will be the default owners for everything in
|
||||
# the repo. They will be requested for review when someone
|
||||
# opens a pull request.
|
||||
* @SkalskiP @onuralpszr
|
||||
|
|
@ -4,13 +4,15 @@ updates:
|
|||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: ⬆️
|
||||
target-branch: "develop"
|
||||
# Python
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: ⬆️
|
||||
target-branch: "develop"
|
||||
|
|
|
|||
|
|
@ -1,33 +1,42 @@
|
|||
|
||||
name: Clear cache
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 1 * *" # Run at midnight on the first day of every month
|
||||
workflow_dispatch:
|
||||
|
||||
# Restrict permissions by default
|
||||
permissions:
|
||||
actions: write
|
||||
actions: write # Required for cache management
|
||||
|
||||
jobs:
|
||||
clear-cache:
|
||||
name: Clear cache
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Clear cache
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
script: |
|
||||
console.log("About to clear")
|
||||
console.log("Starting cache cleanup...")
|
||||
const caches = await github.rest.actions.getActionsCacheList({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
})
|
||||
|
||||
let deletedCount = 0
|
||||
for (const cache of caches.data.actions_caches) {
|
||||
console.log(cache)
|
||||
github.rest.actions.deleteActionsCacheById({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
cache_id: cache.id,
|
||||
})
|
||||
console.log(`Deleting cache: ${cache.key} (${cache.size_in_bytes} bytes)`)
|
||||
try {
|
||||
await github.rest.actions.deleteActionsCacheById({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
cache_id: cache.id,
|
||||
})
|
||||
deletedCount++
|
||||
} catch (error) {
|
||||
console.error(`Failed to delete cache ${cache.key}: ${error.message}`)
|
||||
}
|
||||
}
|
||||
console.log("Clear completed")
|
||||
console.log(`Cache cleanup completed. Deleted ${deletedCount} caches.`)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
name: Combine Dependabot PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * 3" # Wednesday at 01:00
|
||||
workflow_dispatch: # allows you to manually trigger the workflow
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
checks: read
|
||||
|
||||
jobs:
|
||||
combine-prs:
|
||||
name: Combine
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: combine-prs
|
||||
id: combine-prs
|
||||
uses: github/combine-prs@2909f404763c3177a456e052bdb7f2e85d3a7cb3 # v5.2.0
|
||||
with:
|
||||
labels: combined-pr
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
name: Notebook Check Pull Request
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
comment-welcome:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch pull request branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Fetch base develop branch
|
||||
run: git fetch -u "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" develop:develop
|
||||
- name: Create message
|
||||
env:
|
||||
HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
# Preview links and tool usage only needed for notebook changes.
|
||||
readarray -t changed_notebooks < <(git diff --name-only develop | grep '\.ipynb$' || true)
|
||||
if [[ ${#changed_notebooks[@]} == 0 ]]; then
|
||||
echo "No notebooks modified in this pull request."
|
||||
else
|
||||
msg="<h4>Preview</h4>\n"
|
||||
msg+="Preview and run these notebook edits with Google Colab:\n<ul>\n"
|
||||
# Link to PR branch in user's fork that is always current.
|
||||
for fp in "${changed_notebooks[@]}"; do
|
||||
gh_path="${HEAD_REPOSITORY}/blob/${HEAD_REF}/${fp}"
|
||||
colab_url="https://colab.research.google.com/github/${gh_path}"
|
||||
msg+="<li><a href='${colab_url}'>${fp}</a></li>\n"
|
||||
done
|
||||
msg+="</ul>\n"
|
||||
|
||||
reviewnb_url="https://app.reviewnb.com/${GITHUB_REPOSITORY}/pull/${PR_NUM}/files/"
|
||||
msg+="Rendered <a href='${reviewnb_url}'>notebook diffs</a> available on ReviewNB.com.\n"
|
||||
|
||||
msg+="If commits are added to the pull request, synchronize your local branch: <code>git pull origin $HEAD_REF</code>\n"
|
||||
fi
|
||||
echo "MESSAGE=$msg" >> $GITHUB_ENV
|
||||
- name: Post comment
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE_URL: ${{ github.event.pull_request.issue_url }}
|
||||
run: |
|
||||
# Env var defined in previous step. Escape string for JSON.
|
||||
body="$(echo -n -e $MESSAGE | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')"
|
||||
# Add comment to pull request.
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
"${ISSUE_URL}/comments" \
|
||||
--data "{\"body\": $body}"
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
name: 🔧 Poetry Check and Installation Test Workflow
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'poetry.lock'
|
||||
- 'pyproject.toml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'poetry.lock'
|
||||
- 'pyproject.toml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
poetry-tests:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🐍 Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: 📦 Install the base dependencies
|
||||
run: python -m pip install --upgrade poetry
|
||||
|
||||
- name: 🔍 Check the correctness of the project config
|
||||
run: poetry check
|
||||
|
||||
- name: 🚀 Do Install the package Test
|
||||
run: poetry install
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
name: Docs WorkFlow - Develop Tag 📚
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref}}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
pull-requests: write
|
||||
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 🔄 Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 🐍 Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: 📦 Install mkdocs-material
|
||||
run: pip install "mkdocs-material"
|
||||
- name: 📦 Install mkdocstrings[python]
|
||||
run: pip install "mkdocstrings[python]"
|
||||
- name: 📦 Install mkdocs-material[imaging]
|
||||
run: pip install "mkdocs-material[imaging]"
|
||||
- name: 📦 Install mike
|
||||
run: pip install "mike"
|
||||
- name: 📦 Install mkdocs-git-revision-date-localized-plugin
|
||||
run: pip install "mkdocs-git-revision-date-localized-plugin"
|
||||
- name: 📦 Install JupyterLab
|
||||
run: pip install jupyterlab
|
||||
- name: 📦 Install mkdocs-jupyter
|
||||
run: pip install mkdocs-jupyter
|
||||
- name: 📦 Install mkdocs-git-committers-plugin-2
|
||||
run: pip install mkdocs-git-committers-plugin-2
|
||||
- name: ⚙️ Configure git for github-actions
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
- name: 🚀 Deploy MkDoc-Material with mike
|
||||
run: |
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} mike deploy --push develop
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
name: Build and Publish Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
# Ensure only one concurrent deployment
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref}}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Restrict permissions by default
|
||||
permissions:
|
||||
contents: write # Required for committing to gh-pages
|
||||
pages: write # Required for deploying to Pages
|
||||
pull-requests: write # Required for PR comments
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Publish Docs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 🐍 Install uv and set Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🔑 Create GitHub App token (mkdocs)
|
||||
id: mkdocs_token
|
||||
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||
with:
|
||||
app-id: ${{ secrets.MKDOCS_APP_ID }}
|
||||
private-key: ${{ secrets.MKDOCS_PEM }}
|
||||
owner: roboflow
|
||||
repositories: mkdocs-material-insiders
|
||||
|
||||
- name: 🏗️ Install dependencies
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group docs
|
||||
# Install mkdocs-material-insiders using the GitHub App token
|
||||
uv pip install "git+https://roboflow:${{ steps.mkdocs_token.outputs.token }}@github.com/roboflow/mkdocs-material-insiders.git@9.5.49-insiders-4.53.14#egg=mkdocs-material[imaging]"
|
||||
|
||||
- name: ⚙️ Configure git for github-actions
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: 🚀 Deploy Development Docs
|
||||
if: (github.event_name == 'push' && github.ref == 'refs/heads/develop') || github.event_name == 'workflow_dispatch'
|
||||
run: |
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} uv run mike deploy --push develop
|
||||
|
||||
- name: 🚀 Deploy Release Docs
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
run: |
|
||||
latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} uv run mike deploy --push --update-aliases $latest_tag latest
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
name: Publish Supervision Pre-Releases to PyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+a[0-9]"
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+b[0-9]"
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+rc[0-9]"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {} # Explicitly remove all permissions by default
|
||||
|
||||
jobs:
|
||||
publish-pre-release:
|
||||
name: Publish Pre-release Package
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: test
|
||||
url: https://pypi.org/project/supervision/
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
id-token: write # Required for PyPI publishing
|
||||
contents: read # Required for checkout
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
|
||||
- name: 🚀 Publish to PyPi
|
||||
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
||||
with:
|
||||
attestations: true
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
name: Supervision Release Documentation Workflow 📚
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref}}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
pull-requests: write
|
||||
|
||||
|
||||
jobs:
|
||||
doc-build-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 🛎️ Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: 🐍 Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: 📦 Install mkdocs-material
|
||||
run: pip install "mkdocs-material"
|
||||
- name: 📦 Install mkdocstrings[python]
|
||||
run: pip install "mkdocstrings[python]"
|
||||
- name: 📦 Install mkdocs-material[imaging]
|
||||
run: pip install "mkdocs-material[imaging]"
|
||||
- name: 📦 Install mike
|
||||
run: pip install "mike"
|
||||
- name: 📦 Install mkdocs-git-revision-date-localized-plugin
|
||||
run: pip install "mkdocs-git-revision-date-localized-plugin"
|
||||
- name: 📦 Install JupyterLab
|
||||
run: pip install jupyterlab
|
||||
- name: 📦 Install mkdocs-jupyter
|
||||
run: pip install mkdocs-jupyter
|
||||
- name: 📦 Install mkdocs-git-committers-plugin-2
|
||||
run: pip install mkdocs-git-committers-plugin-2
|
||||
- name: ⚙️ Configure git for github-actions 👷
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
- name: 🚀 Deploy MkDoc-Material 📚
|
||||
run: |
|
||||
latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} mike deploy --push --update-aliases $latest_tag latest
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
name: Publish Supervision Releases to PyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {} # Explicitly remove all permissions by default
|
||||
|
||||
jobs:
|
||||
publish-release:
|
||||
name: Publish Release Package
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release
|
||||
url: https://pypi.org/project/supervision/
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
id-token: write # Required for PyPI publishing
|
||||
contents: read # Required for checkout
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
|
||||
- name: 🚀 Publish to PyPi
|
||||
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
||||
with:
|
||||
attestations: true
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
name: Publish Supervision Pre-Releases to PyPI and TestPyPI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+a[0-9]"
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+b[0-9]"
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+rc[0-9]"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-publish-pre-release-pypi:
|
||||
name: Build and publish to PyPI
|
||||
runs-on: ubuntu-latest
|
||||
environment: test
|
||||
permissions:
|
||||
id-token: write
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 🛎️ Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
- name: 🐍 Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
python -m pip install --upgrade build twine
|
||||
python -m build
|
||||
twine check --strict dist/*
|
||||
|
||||
- name: 🚀 Publish to PyPi
|
||||
uses: pypa/gh-action-pypi-publish@release/v1.10
|
||||
|
||||
- name: 🚀 Publish to Test-PyPi
|
||||
uses: pypa/gh-action-pypi-publish@release/v1.10
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
name: Publish Supervision Releases to TestPyPI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {} # Explicitly remove all permissions by default
|
||||
|
||||
jobs:
|
||||
publish-testpypi:
|
||||
name: Publish Release Package
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release
|
||||
url: https://pypi.org/project/supervision/
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
id-token: write # Required for PyPI publishing
|
||||
contents: read # Required for checkout
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
|
||||
- name: 🚀 Publish to Test-PyPi
|
||||
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
attestations: true
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
name: Publish Supervision Releases to PyPI and TestPyPI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-publish-pre-release:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
permissions:
|
||||
id-token: write
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 🛎️ Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
- name: 🐍 Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
python -m pip install --upgrade build twine
|
||||
python -m build
|
||||
twine check --strict dist/*
|
||||
|
||||
- name: 🚀 Publish to PyPi
|
||||
uses: pypa/gh-action-pypi-publish@release/v1.10
|
||||
|
||||
- name: 🚀 Publish to Test-PyPi
|
||||
uses: pypa/gh-action-pypi-publish@release/v1.10
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
|
@ -4,18 +4,34 @@ on:
|
|||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
# Restrict permissions by default
|
||||
permissions:
|
||||
contents: read # Required for checkout
|
||||
checks: write # Required for test reporting
|
||||
|
||||
jobs:
|
||||
docs-build-test:
|
||||
name: Test docs build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 🔄 Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: 🐍 Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: 🏗️ Install dependencies and Test Docs Build
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 🐍 Install uv and set Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
- name: 🏗️ Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install "mkdocs-material" "mkdocstrings[python]" "mkdocs-material[imaging]" mike "mkdocs-git-revision-date-localized-plugin" jupyterlab mkdocs-jupyter mkdocs-git-committers-plugin-2
|
||||
mkdocs build --verbose
|
||||
uv pip install -r pyproject.toml --group docs
|
||||
|
||||
- name: 🧪 Test Docs Build
|
||||
run: uv run mkdocs build --verbose
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
name: Python 3.8 - Min Dep Test WorkFlow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
build-min-dep-test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8"]
|
||||
steps:
|
||||
- name: 🛎️ Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: 🐍 Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
# id based on python version
|
||||
id: python-setup
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install \
|
||||
attrs==23.1.0 \
|
||||
certifi==2023.7.22 \
|
||||
charset-normalizer==2.0.12 \
|
||||
cycler==0.12.1 \
|
||||
exceptiongroup==1.1.3 \
|
||||
fonttools==4.43.1 \
|
||||
idna==3.4 \
|
||||
iniconfig==2.0.0 \
|
||||
kiwisolver==1.4.5 \
|
||||
matplotlib==3.5.0 \
|
||||
numpy==1.21.2 \
|
||||
opencv-python==4.5.5.64 \
|
||||
Pillow==10.1.0 \
|
||||
packaging==23.2 \
|
||||
pluggy==1.3.0 \
|
||||
pyparsing==3.1.1 \
|
||||
pytest==7.2.0 \
|
||||
python-dateutil==2.8.2 \
|
||||
PyYAML==5.3 \
|
||||
requests==2.26.0 \
|
||||
scipy==1.10.0 \
|
||||
setuptools-scm==8.0.4 \
|
||||
six==1.16.0 \
|
||||
tomli==2.0.1 \
|
||||
tqdm==4.62.3 \
|
||||
typing_extensions==4.8.0 \
|
||||
urllib3==1.26.18 \
|
||||
defusedxml==0.7.1
|
||||
|
||||
- name: 🧪 Test
|
||||
run: "python -m pytest ./test"
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
name: Test WorkFlow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
build-dev-test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
steps:
|
||||
- name: 🛎️ Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: 🐍 Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install .
|
||||
pip install pytest
|
||||
|
||||
- name: 🧪 Test
|
||||
run: "python -m pytest ./test"
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
name: 🔧 Pytest/Test Workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
name: Import Test and Pytest Run
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🚀 Install Packages
|
||||
run: uv pip install -r pyproject.toml --group dev --group docs --extra metrics
|
||||
|
||||
- name: 🧪 Run the Import test
|
||||
run: uv run python -c "import supervision; from supervision import assets; from supervision import metrics; print(supervision.__version__)"
|
||||
|
||||
- name: 🧪 Run the Test
|
||||
run: uv run pytest
|
||||
|
|
@ -25,14 +25,14 @@ repos:
|
|||
- id: mixed-line-ending
|
||||
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: '1.7.10'
|
||||
rev: '1.8.6'
|
||||
hooks:
|
||||
- id: bandit
|
||||
args: ["-c", "pyproject.toml"]
|
||||
additional_dependencies: ["bandit[toml]"]
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.7.3
|
||||
rev: v0.12.3
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
|
@ -48,8 +48,16 @@ repos:
|
|||
# args: ["--number"]
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.3.0
|
||||
rev: v2.4.1
|
||||
hooks:
|
||||
- id: codespell
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.20.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py310-plus"]
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
|
|
|||
|
|
@ -128,15 +128,26 @@ PRs must pass all tests and linting requirements before they can be merged.
|
|||
|
||||
Before starting your work on the project, set up your development environment:
|
||||
|
||||
1. Clone your fork of the project:
|
||||
1. Clone your fork of the project (recommended to use shallow clone of develop branch):
|
||||
|
||||
**Option A: Recommended for most contributors (shallow clone of develop branch):**
|
||||
|
||||
```bash
|
||||
git clone --depth 1 -b develop https://github.com/YOUR_USERNAME/supervision.git
|
||||
cd supervision
|
||||
```
|
||||
|
||||
Replace `YOUR_USERNAME` with your GitHub username.
|
||||
|
||||
> Note: Using `--depth 1` creates a shallow clone with minimal history and `-b develop` ensures you start with the development branch. This significantly reduces download size while providing everything needed to contribute.
|
||||
|
||||
**Option B: Full repository clone (if you need complete history):**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/supervision.git
|
||||
cd supervision
|
||||
```
|
||||
|
||||
Replace `YOUR_USERNAME` with your GitHub username.
|
||||
|
||||
2. Create and activate a virtual environment:
|
||||
|
||||
```bash
|
||||
|
|
@ -144,31 +155,20 @@ Before starting your work on the project, set up your development environment:
|
|||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
3. Install Poetry:
|
||||
3. Install `uv`:
|
||||
|
||||
Using pip:
|
||||
|
||||
```bash
|
||||
pip install -U pip setuptools
|
||||
pip install poetry
|
||||
```
|
||||
|
||||
Or using pipx (recommended for global installation):
|
||||
|
||||
```bash
|
||||
pipx install poetry
|
||||
```
|
||||
Follow the instructions on the [uv installation page](https://docs.astral.sh/uv/getting-started/installation/).
|
||||
|
||||
4. Install project dependencies:
|
||||
|
||||
```bash
|
||||
poetry install
|
||||
uv pip install -r pyproject.toml --extra dev --extra docs --extra metrics
|
||||
```
|
||||
|
||||
5. Run pytest to verify the setup:
|
||||
|
||||
```bash
|
||||
poetry run pytest
|
||||
uv run pytest
|
||||
```
|
||||
|
||||
## 🎨 Code Style and Quality
|
||||
|
|
@ -181,7 +181,7 @@ Furthermore, we have integrated a pre-commit GitHub Action into our workflow. Th
|
|||
|
||||
To run the pre-commit tool, follow these steps:
|
||||
|
||||
1. Install pre-commit by running the following command: `poetry install --with dev`. It will not only install pre-commit but also install all the deps and dev-deps of project
|
||||
1. Install pre-commit by running the following command: `uv pip install -r pyproject.toml --extra dev`. It will not only install pre-commit but also install all the deps and dev-deps of project
|
||||
|
||||
2. Once pre-commit is installed, navigate to the project's root directory.
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ So far, **there is no type checking with mypy**. See [issue](https://github.com/
|
|||
|
||||
The `supervision` documentation is stored in a folder called `docs`. The project documentation is built using `mkdocs`.
|
||||
|
||||
To run the documentation, install the project requirements with `poetry install --with dev`. Then, run `mkdocs serve` to start the documentation server.
|
||||
To run the documentation, install the project requirements with `uv pip install -r pyproject.toml --extra dev --extra docs`. Then, run `mkdocs serve` to start the documentation server.
|
||||
|
||||
You can learn more about mkdocs on the [mkdocs website](https://www.mkdocs.org/).
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
## 💻 install
|
||||
|
||||
Pip install the supervision package in a
|
||||
[**Python>=3.8**](https://www.python.org/) environment.
|
||||
[**Python>=3.9**](https://www.python.org/) environment.
|
||||
|
||||
```bash
|
||||
pip install supervision
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q ultralytics"
|
||||
"!pip install -q \"ultralytics<=8.3.40\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Assets
|
||||
|
|
@ -8,17 +7,6 @@ status: new
|
|||
Supervision offers an assets download utility that allows you to download video files
|
||||
that you can use in your demos.
|
||||
|
||||
## Install extra
|
||||
|
||||
To install the Supervision assets utility, you can use `pip`. This utility is available
|
||||
as an extra within the Supervision package.
|
||||
|
||||
!!! example "pip install"
|
||||
|
||||
```bash
|
||||
pip install "supervision[assets]"
|
||||
```
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.assets.downloader.download_assets.download_assets">download_assets</a></h2>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,179 @@
|
|||
# CHANGELOG
|
||||
# Changelog
|
||||
|
||||
### 0.26.0 <small>Jul 16, 2025</small>
|
||||
|
||||
!!! failure "Removed"
|
||||
`supervision-0.26.0` drops `python3.8` support and upgrade all codes to `python3.9` syntax style.
|
||||
|
||||
!!! info "Tip"
|
||||
Supervision’s documentation theme now has a fresh look that is consistent with the documentations of all Roboflow open-source projects. ([#1858](https://github.com/roboflow/supervision/pull/1858))
|
||||
|
||||
- Added [#1774](https://github.com/roboflow/supervision/pull/1774): Support for the IOS (Intersection over Smallest) overlap metric that measures how much of the smaller object is covered by the larger one in [`sv.Detections.with_nms`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.with_nms), [`sv.Detections.with_nmm`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.with_nmm), [`sv.box_iou_batch`](https://supervision.roboflow.com/0.26.0/detection/utils/iou_and_nms/#supervision.detection.utils.iou_and_nms.box_iou_batch), and [`sv.mask_iou_batch`](https://supervision.roboflow.com/0.26.0/detection/utils/iou_and_nms/#supervision.detection.utils.iou_and_nms.mask_iou_batch).
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import supervision as sv
|
||||
|
||||
boxes_true = np.array([
|
||||
[100, 100, 200, 200],
|
||||
[300, 300, 400, 400]
|
||||
])
|
||||
boxes_detection = np.array([
|
||||
[150, 150, 250, 250],
|
||||
[320, 320, 420, 420]
|
||||
])
|
||||
|
||||
sv.box_iou_batch(
|
||||
boxes_true=boxes_true,
|
||||
boxes_detection=boxes_detection,
|
||||
overlap_metric=sv.OverlapMetric.IOU
|
||||
)
|
||||
|
||||
# array([[0.14285714, 0. ],
|
||||
# [0. , 0.47058824]])
|
||||
|
||||
sv.box_iou_batch(
|
||||
boxes_true=boxes_true,
|
||||
boxes_detection=boxes_detection,
|
||||
overlap_metric=sv.OverlapMetric.IOS
|
||||
)
|
||||
|
||||
# array([[0.25, 0. ],
|
||||
# [0. , 0.64]])
|
||||
```
|
||||
|
||||
- Added [#1874](https://github.com/roboflow/supervision/pull/1874): [`sv.box_iou`](https://supervision.roboflow.com/0.26.0/detection/utils/iou_and_nms/#supervision.detection.utils.iou_and_nms.box_iou) that efficiently computes the Intersection over Union (IoU) between two individual bounding boxes.
|
||||
|
||||
- Added [#1816](https://github.com/roboflow/supervision/pull/1816): Support for frame limitations and progress bar in [`sv.process_video`](https://supervision.roboflow.com/0.26.0/utils/video/#supervision.utils.video.process_video).
|
||||
|
||||
- Added [#1788](https://github.com/roboflow/supervision/pull/1788): Support for creating [`sv.KeyPoints`](https://supervision.roboflow.com/0.26.0/keypoint/core/#supervision.keypoint.core.KeyPoints) objects from [ViTPose](https://huggingface.co/docs/transformers/en/model_doc/vitpose) and [ViTPose++](https://huggingface.co/docs/transformers/en/model_doc/vitpose#vitpose-models) inference results via [`sv.KeyPoints.from_transformers`](https://supervision.roboflow.com/0.26.0/keypoint/core/#supervision.keypoint.core.KeyPoints.from_transformers).
|
||||
|
||||
- Added [#1823](https://github.com/roboflow/supervision/pull/1823): [`sv.xyxy_to_xcycarh`](https://supervision.roboflow.com/0.26.0/detection/utils/converters/#supervision.detection.utils.converters.xyxy_to_xcycarh) function to convert bounding box coordinates from `(x_min, y_min, x_max, y_max)` into measurement space to format `(center x, center y, aspect ratio, height)`, where the aspect ratio is `width / height`.
|
||||
|
||||
- Added [#1788](https://github.com/roboflow/supervision/pull/1788): [`sv.xyxy_to_xywh`](https://supervision.roboflow.com/0.26.0/detection/utils/converters/#supervision.detection.utils.converters.xyxy_to_xywh) function to convert bounding box coordinates from `(x_min, y_min, x_max, y_max)` format to `(x, y, width, height)` format.
|
||||
|
||||
- Changed [#1820](https://github.com/roboflow/supervision/pull/1820): [`sv.LabelAnnotator`](https://supervision.roboflow.com/0.26.0/detection/annotators/#supervision.annotators.core.LabelAnnotator) now supports the `smart_position` parameter to automatically keep labels within frame boundaries, and the `max_line_length` parameter to control text wrapping for long or multi-line labels.
|
||||
|
||||
- Changed [#1825](https://github.com/roboflow/supervision/pull/1825): [`sv.LabelAnnotator`](https://supervision.roboflow.com/0.26.0/detection/annotators/#supervision.annotators.core.LabelAnnotator) now supports non-string labels.
|
||||
|
||||
- Changed [#1792](https://github.com/roboflow/supervision/pull/1792): [`sv.Detections.from_vlm`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.from_vlm) now supports parsing bounding boxes and segmentation masks from responses generated by [Google Gemini models](https://ai.google.dev/gemini-api/docs/vision).
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
gemini_response_text = """```json
|
||||
[
|
||||
{"box_2d": [543, 40, 728, 200], "label": "cat", "id": 1},
|
||||
{"box_2d": [653, 352, 820, 522], "label": "dog", "id": 2}
|
||||
]
|
||||
```"""
|
||||
|
||||
detections = sv.Detections.from_vlm(
|
||||
sv.VLM.GOOGLE_GEMINI_2_5,
|
||||
gemini_response_text,
|
||||
resolution_wh=(1000, 1000),
|
||||
classes=['cat', 'dog'],
|
||||
)
|
||||
|
||||
detections.xyxy
|
||||
# array([[543., 40., 728., 200.], [653., 352., 820., 522.]])
|
||||
|
||||
detections.data
|
||||
# {'class_name': array(['cat', 'dog'], dtype='<U26')}
|
||||
|
||||
detections.class_id
|
||||
# array([0, 1])
|
||||
```
|
||||
|
||||
- Changed [#1878](https://github.com/roboflow/supervision/pull/1878): [`sv.Detections.from_vlm`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.from_vlm) now supports parsing bounding boxes from responses generated by [Moondream](https://github.com/vikhyat/moondream).
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
moondream_result = {
|
||||
'objects': [
|
||||
{
|
||||
'x_min': 0.5704046934843063,
|
||||
'y_min': 0.20069346576929092,
|
||||
'x_max': 0.7049859315156937,
|
||||
'y_max': 0.3012596592307091
|
||||
},
|
||||
{
|
||||
'x_min': 0.6210969910025597,
|
||||
'y_min': 0.3300672620534897,
|
||||
'x_max': 0.8417936339974403,
|
||||
'y_max': 0.4961046129465103
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
detections = sv.Detections.from_vlm(
|
||||
sv.VLM.MOONDREAM,
|
||||
moondream_result,
|
||||
resolution_wh=(1000, 1000),
|
||||
)
|
||||
|
||||
detections.xyxy
|
||||
# array([[1752.28, 818.82, 2165.72, 1229.14],
|
||||
# [1908.01, 1346.67, 2585.99, 2024.11]])
|
||||
```
|
||||
|
||||
- Changed [#1709](https://github.com/roboflow/supervision/pull/1790): [`sv.Detections.from_vlm`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.from_vlm) now supports parsing bounding boxes from responses generated by [Qwen-2.5 VL](https://github.com/QwenLM/Qwen2.5-VL).
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
qwen_2_5_vl_result = """```json
|
||||
[
|
||||
{"bbox_2d": [139, 768, 315, 954], "label": "cat"},
|
||||
{"bbox_2d": [366, 679, 536, 849], "label": "dog"}
|
||||
]
|
||||
```"""
|
||||
|
||||
detections = sv.Detections.from_vlm(
|
||||
sv.VLM.QWEN_2_5_VL,
|
||||
qwen_2_5_vl_result,
|
||||
input_wh=(1000, 1000),
|
||||
resolution_wh=(1000, 1000),
|
||||
classes=['cat', 'dog'],
|
||||
)
|
||||
|
||||
detections.xyxy
|
||||
# array([[139., 768., 315., 954.], [366., 679., 536., 849.]])
|
||||
|
||||
detections.class_id
|
||||
# array([0, 1])
|
||||
|
||||
detections.data
|
||||
# {'class_name': array(['cat', 'dog'], dtype='<U10')}
|
||||
|
||||
detections.class_id
|
||||
# array([0, 1])
|
||||
```
|
||||
|
||||
- Changed [#1786](https://github.com/roboflow/supervision/pull/1786): Significantly improved the speed of HSV color mapping in [`sv.HeatMapAnnotator`](https://supervision.roboflow.com/0.26.0/detection/annotators/#supervision.annotators.core.HeatMapAnnotator), achieving approximately 28x faster performance on 1920x1080 frames.
|
||||
|
||||
- Fix [#1834](https://github.com/roboflow/supervision/pull/1834): Supervision’s [`sv.MeanAveragePrecision`](https://supervision.roboflow.com/0.26.0/metrics/mean_average_precision/#supervision.metrics.mean_average_precision.MeanAveragePrecision) is now fully aligned with [pycocotools](https://github.com/ppwwyyxx/cocoapi), the official COCO evaluation tool, ensuring accurate and standardized metrics. This update enabled us to launch a new version of the [Computer Vision Model Leaderboard](https://leaderboard.roboflow.com/).
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
from supervision.metrics import MeanAveragePrecision
|
||||
|
||||
predictions = sv.Detections(...)
|
||||
targets = sv.Detections(...)
|
||||
|
||||
map_metric = MeanAveragePrecision()
|
||||
map_metric.update(predictions, targets).compute()
|
||||
|
||||
# Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.464
|
||||
# Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.637
|
||||
# Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.203
|
||||
# Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.284
|
||||
# Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.497
|
||||
# Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.629
|
||||
```
|
||||
|
||||
- Fix [#1767](https://github.com/roboflow/supervision/pull/1767): Fixed losing `sv.Detections.data` when detections filtering.
|
||||
|
||||
### 0.25.0 <small>Nov 12, 2024</small>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,21 +7,19 @@ status: deprecated
|
|||
|
||||
These features are phased out due to better alternatives or potential issues in future versions. Deprecated functionalities are supported for **five subsequent releases**, providing time for users to transition to updated methods.
|
||||
|
||||
- Constructing [`DetectionDataset`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.DetectionDataset) and [`ClassificationDataset`](https://supervision.roboflow.com/latest/datasets/core/#supervision.dataset.core.ClassificationDataset) with parameter `images` as `Dict[str, np.ndarray]` will be removed in `supervision-0.26.0`. Please pass a list of paths `List[str]` instead.
|
||||
|
||||
- The `DetectionDataset.images` property will be removed in `supervision-0.26.0`. Please loop over images with `for path, image, annotation in dataset:`, as that does not require loading all images into memory.
|
||||
|
||||
- `BoundingBoxAnnotator` has been renamed to `BoxAnnotator` after the old implementation of [`BoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoxAnnotator) has been removed. `BoundingBoxAnnotator` will be removed in `supervision-0.26.0`.
|
||||
|
||||
- `overlap_filter_strategy` in [`InferenceSlicer.__init__`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/) is deprecated and will be removed in `supervision-0.27.0`. Use `overlap_strategy` instead.
|
||||
|
||||
- `overlap_ratio_wh` in [`InferenceSlicer.__init__`](https://supervision.roboflow.com/latest/detection/tools/inference_slicer/) is deprecated and will be removed in `supervision-0.27.0`. Use `overlap_wh` instead.
|
||||
- `sv.LMM` enum is deprecated and will be removed in `supervision-0.31.0`. Use `sv.VLM` instead.
|
||||
- [`sv.Detections.from_lmm`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.from_lmm) property is deprecated and will be removed in `supervision-0.31.0`. Use [`sv.Detections.from_vlm`](https://supervision.roboflow.com/0.26.0/detection/core/#supervision.detection.core.Detections.from_vlm) instead.
|
||||
|
||||
# Removed
|
||||
|
||||
### 0.25.0
|
||||
### 0.26.0
|
||||
|
||||
- The `sv.DetectionDataset.images` property has been removed in `supervision-0.26.0`. Please loop over images with `for path, image, annotation in dataset:`, as that does not require loading all images into memory. Also, constructing `sv.DetectionDataset` with parameter `images` as `Dict[str, np.ndarray]` is deprecated and has been removed in `supervision-0.26.0`. Please pass a list of paths `List[str]` instead.
|
||||
- The name `sv.BoundingBoxAnnotator` is deprecated and has been removed in `supervision-0.26.0`. It has been renamed to [`sv.BoxAnnotator`](https://supervision.roboflow.com/0.22.0/detection/annotators/#supervision.annotators.core.BoxAnnotator).
|
||||
|
||||
No removals in this version!
|
||||
|
||||
### 0.24.0
|
||||
|
||||
|
|
@ -35,12 +33,12 @@ No removals in this version!
|
|||
|
||||
### 0.22.0
|
||||
|
||||
- `Detections.from_roboflow` is removed as of `supervision-0.22.0`. Use [`Detections.from_inference`](detection/core.md/#supervision.detection.core.Detections.from_inference) instead.
|
||||
- The method `Color.white()` was removed as of `supervision-0.22.0`. Use the constant `Color.WHITE` instead.
|
||||
- The method `Color.black()` was removed as of `supervision-0.22.0`. Use the constant `Color.BLACK` instead.
|
||||
- The method `Color.red()` was removed as of `supervision-0.22.0`. Use the constant `Color.RED` instead.
|
||||
- The method `Color.green()` was removed as of `supervision-0.22.0`. Use the constant `Color.GREEN` instead.
|
||||
- The method `Color.blue()` was removed as of `supervision-0.22.0`. Use the constant `Color.BLUE` instead.
|
||||
- The method `ColorPalette.default()` was removed as of `supervision-0.22.0`. Use the constant [`ColorPalette.DEFAULT`](/utils/draw/#supervision.draw.color.ColorPalette.DEFAULT) instead.
|
||||
- `BoxAnnotator` was removed as of `supervision-0.22.0`, however `BoundingBoxAnnotator` was immediately renamed to `BoxAnnotator`. Use [`BoxAnnotator`](detection/annotators.md/#supervision.annotators.core.BoxAnnotator) and [`LabelAnnotator`](detection/annotators.md/#supervision.annotators.core.LabelAnnotator) instead of the old `BoxAnnotator`.
|
||||
- The method `FPSMonitor.__call__` was removed as of `supervision-0.22.0`. Use the attribute [`FPSMonitor.fps`](utils/video.md/#supervision.utils.video.FPSMonitor.fps) instead.
|
||||
- `sv.Detections.from_roboflow` is removed as of `supervision-0.22.0`. Use [`Detections.from_inference`](detection/core.md/#supervision.detection.core.Detections.from_inference) instead.
|
||||
- The method `sv.Color.white()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.WHITE` instead.
|
||||
- The method `sv.Color.black()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.BLACK` instead.
|
||||
- The method `sv.Color.red()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.RED` instead.
|
||||
- The method `sv.Color.green()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.GREEN` instead.
|
||||
- The method `sv.Color.blue()` was removed as of `supervision-0.22.0`. Use the constant `sv.Color.BLUE` instead.
|
||||
- The method `sv.ColorPalette.default()` was removed as of `supervision-0.22.0`. Use the constant [`ColorPalette.DEFAULT`](/utils/draw/#supervision.draw.color.ColorPalette.DEFAULT) instead.
|
||||
- `sv.BoxAnnotator` was removed as of `supervision-0.22.0`, however `sv.BoundingBoxAnnotator` was immediately renamed to `sv.BoxAnnotator`. Use [`BoxAnnotator`](detection/annotators.md/#supervision.annotators.core.BoxAnnotator) and [`LabelAnnotator`](detection/annotators.md/#supervision.annotators.core.LabelAnnotator) instead of the old `sv.BoxAnnotator`.
|
||||
- The method `sv.FPSMonitor.__call__` was removed as of `supervision-0.22.0`. Use the attribute [`sv.FPSMonitor.fps`](utils/video.md/#supervision.utils.video.FPSMonitor.fps) instead.
|
||||
|
|
|
|||
|
|
@ -234,7 +234,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -255,7 +256,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -283,7 +285,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -314,7 +317,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -341,24 +345,32 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
=== "Crop"
|
||||
<!-- === "Crop"
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
image = ...
|
||||
detections = sv.Detections(...)
|
||||
image = ...
|
||||
detections = sv.Detections(...)
|
||||
|
||||
crop_annotator = sv.CropAnnotator()
|
||||
annotated_frame = crop_annotator.annotate(
|
||||
scene=image.copy(),
|
||||
detections=detections
|
||||
)
|
||||
```
|
||||
crop_annotator = sv.CropAnnotator()
|
||||
annotated_frame = crop_annotator.annotate(
|
||||
scene=image.copy(),
|
||||
detections=detections
|
||||
)
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
-->
|
||||
|
||||
=== "Blur"
|
||||
|
||||
|
|
@ -377,7 +389,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -398,7 +411,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -429,7 +443,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -458,7 +473,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -479,7 +495,31 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
<div class="result" markdown>
|
||||
|
||||

|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
=== "Comparison"
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
image = ...
|
||||
detections_1 = sv.Detections(...)
|
||||
detections_2 = sv.Detections(...)
|
||||
|
||||
comparison_annotator = sv.ComparisonAnnotator()
|
||||
annotated_frame = comparison_annotator.annotate(
|
||||
scene=image.copy(),
|
||||
detections_1=detections_1,
|
||||
detections_2=detections_2
|
||||
)
|
||||
```
|
||||
|
||||
<div class="result" markdown>
|
||||
|
||||
{ align=center width="800" }
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -622,6 +662,12 @@ Annotators accept detections and apply box or mask visualizations to the detecti
|
|||
|
||||
:::supervision.annotators.core.BackgroundOverlayAnnotator
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.annotators.core.ComparisonAnnotator">ComparisonAnnotator</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.annotators.core.ComparisonAnnotator
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.annotators.core.ColorLookup">ColorLookup</a></h2>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# Double Detection Filter
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.overlap_filter.OverlapFilter">OverlapFilter</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.overlap_filter.OverlapFilter
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.overlap_filter.box_non_max_suppression">box_non_max_suppression</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.overlap_filter.box_non_max_suppression
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.overlap_filter.mask_non_max_suppression">mask_non_max_suppression</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.overlap_filter.mask_non_max_suppression
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.overlap_filter.box_non_max_merge">box_non_max_merge</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.overlap_filter.box_non_max_merge
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
<div class="md-typeset">
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Detection Utils
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.box_iou_batch">box_iou_batch</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.box_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.mask_iou_batch">mask_iou_batch</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.mask_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.oriented_box_iou_batch">oriented_box_iou_batch</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.oriented_box_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.polygon_to_mask">polygon_to_mask</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.polygon_to_mask
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.mask_to_xyxy">mask_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.mask_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.mask_to_polygons">mask_to_polygons</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.mask_to_polygons
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.polygon_to_xyxy">polygon_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.polygon_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.filter_polygons_by_area">filter_polygons_by_area</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.filter_polygons_by_area
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.move_boxes">move_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.move_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.move_masks">move_masks</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.move_masks
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.scale_boxes">scale_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.scale_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.clip_boxes">clip_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.clip_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.pad_boxes">pad_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.pad_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.xywh_to_xyxy">xywh_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.xywh_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.xcycwh_to_xyxy">xcycwh_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.xcycwh_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.contains_holes">contains_holes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.contains_holes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.contains_multiple_segments">contains_multiple_segments</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.contains_multiple_segments
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Boxes Utils
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.boxes.move_boxes">move_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.boxes.move_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.boxes.scale_boxes">scale_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.boxes.scale_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.boxes.utils.clip_boxes">clip_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.boxes.clip_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.boxes.pad_boxes">pad_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.boxes.pad_boxes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.boxes.denormalize_boxes">denormalize_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.boxes.denormalize_boxes
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Converters Utils
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.xyxy_to_xywh">xyxy_to_xywh</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.xyxy_to_xywh
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.xywh_to_xyxy">xywh_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.xywh_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.xyxy_to_xcycarh">xyxy_to_xcycarh</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.xyxy_to_xcycarh
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.xcycwh_to_xyxy">xcycwh_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.xcycwh_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.xyxy_to_polygons">xyxy_to_polygons</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.xyxy_to_polygons
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.mask_to_xyxy">mask_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.mask_to_xyxy
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.mask_to_polygons">mask_to_polygons</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.mask_to_polygons
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.polygon_to_mask">polygon_to_mask</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.polygon_to_mask
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.converters.polygon_to_xyxy">polygon_to_xyxy</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.converters.polygon_to_xyxy
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# IoU and NMS Utils
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.OverlapFilter">OverlapFilter</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.OverlapFilter
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.OverlapMetric">OverlapMetric</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.OverlapMetric
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.utils.box_iou">box_iou</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.box_iou
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.box_iou_batch">box_iou_batch</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.box_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.box_iou_batch_with_jaccard">box_iou_batch_with_jaccard</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.box_iou_batch_with_jaccard
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.mask_iou_batch">mask_iou_batch</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.mask_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.oriented_box_iou_batch">oriented_box_iou_batch</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.oriented_box_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.box_non_max_suppression">box_non_max_suppression</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.box_non_max_suppression
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.mask_non_max_suppression">mask_non_max_suppression</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.mask_non_max_suppression
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.box_non_max_merge">box_non_max_merge</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.box_non_max_merge
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.iou_and_nms.mask_non_max_merge">mask_non_max_merge</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.iou_and_nms.mask_non_max_merge
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Masks Utils
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.masks.move_masks">move_masks</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.masks.move_masks
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.masks.contains_holes">contains_holes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.masks.contains_holes
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.masks.contains_multiple_segments">contains_multiple_segments</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.masks.contains_multiple_segments
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Polygons Utils
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.polygons.filter_polygons_by_area">filter_polygons_by_area</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.polygons.filter_polygons_by_area
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.polygons.approximate_polygon">approximate_polygon</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.polygons.approximate_polygon
|
||||
|
|
@ -0,0 +1,441 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||

|
||||
|
||||
# Benchmark a Model
|
||||
|
||||
Have you ever trained multiple detection models and wondered which one performs best on your specific use case? Or maybe you've downloaded a pre-trained model and want to verify its performance on your dataset? Model benchmarking is essential for making informed decisions about which model to deploy in production.
|
||||
|
||||
This guide will show an easy way to benchmark your results using `supervision`. It will go over:
|
||||
|
||||
1. [Loading a dataset](#loading-a-dataset)
|
||||
2. [Loading a model](#loading-a-model)
|
||||
3. [Benchmarking Basics](#benchmarking-basics)
|
||||
4. [Running a Model](#running-a-model)
|
||||
5. [Remapping Classes](#remapping-classes)
|
||||
6. [Visual Benchmarking](#visual-benchmarking)
|
||||
7. [Benchmarking Metrics](#benchmarking-metrics)
|
||||
8. [Mean Average Precision (mAP)](#mean-average-precision-map)
|
||||
9. [F1 Score](#f1-score)
|
||||
10. [Bonus: Model Leaderboard](#model-leaderboard)
|
||||
|
||||
This guide will use an instance segmentation model, but it applies to object detection, instance segmentation, and oriented bounding box models (OBB) too.
|
||||
|
||||
A condensed version of this guide is available as a [Colab Notebook](https://colab.research.google.com/drive/1HoOY9pZoVwGiRMmLHtir0qT6Uj45w6Ps?usp=sharing).
|
||||
|
||||
## Loading a Dataset
|
||||
|
||||
Suppose you start with a dataset. Perhaps you found it on [Universe](https://universe.roboflow.com/); perhaps you [labeled your own](https://roboflow.com/how-to-label/yolo11). In either case, this guide assumes you know of a labelled dataset at hand.
|
||||
|
||||
We'll use the following libraries:
|
||||
|
||||
- `roboflow` to manage the dataset and deploy models
|
||||
- `inference` to run the models
|
||||
- `supervision` to evaluate the model results
|
||||
|
||||
```bash
|
||||
pip install roboflow supervision
|
||||
pip install git+https://github.com/roboflow/inference.git@linas/allow-latest-rc-supervision
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
We're updating `inference` at the moment. Please install it as shown above.
|
||||
|
||||
Here's how you can download a dataset:
|
||||
|
||||
```python
|
||||
from roboflow import Roboflow
|
||||
|
||||
rf = Roboflow(api_key="<YOUR_API_KEY>")
|
||||
project = rf.workspace("<WORKSPACE_NAME>").project("<PROJECT_NAME>")
|
||||
dataset = project.version(<DATASET_VERSION_NUMBER>).download("<FORMAT>")
|
||||
```
|
||||
|
||||
If your dataset is from Universe, go to `Dataset` > `Download Dataset` > select the format (e.g. `YOLOv11`) > `Show download code`.
|
||||
|
||||
If labeling your own data, go to the [dashboard](https://app.roboflow.com/) and check this [guide](https://docs.roboflow.com/api-reference/workspace-and-project-ids) to find your workspace and project IDs.
|
||||
|
||||
In this guide, we shall use a small [Corgi v2](https://universe.roboflow.com/model-examples/segmented-animals-basic) dataset. It is well-labeled and comes with a test set.
|
||||
|
||||
```python
|
||||
from roboflow import Roboflow
|
||||
|
||||
rf = Roboflow(api_key="<YOUR_API_KEY>")
|
||||
project = rf.workspace("fbamse1-gm2os").project("corgi-v2")
|
||||
dataset = project.version(4).download("yolov11")
|
||||
```
|
||||
|
||||
This will create a folder called `Corgi-v2-4` with the dataset in the current working directory, with `train`, `test`, and `valid` folders and a `data.yaml` file.
|
||||
|
||||
## Loading a Model
|
||||
|
||||
Let's load a model.
|
||||
|
||||
=== "Inference, Local"
|
||||
|
||||
Roboflow supports a range of state-of-the-art [pre-trained models](https://inference.roboflow.com/quickstart/aliases/) for object detection, instance segmentation, and pose tracking. You don't even need an API key!
|
||||
|
||||
Let's load such a model with inference [`inference`](https://inference.roboflow.com/).
|
||||
|
||||
```python
|
||||
from inference import get_model
|
||||
|
||||
model = get_model(model_id="yolov11s-seg-640")
|
||||
```
|
||||
|
||||
=== "Inference, Deployed"
|
||||
|
||||
You can train and deploy a model without leaving the Roboflow platform. See this [guide](https://docs.roboflow.com/train/train/train-from-scratch) for more details.
|
||||
|
||||
To load a model, you can use inference:
|
||||
|
||||
```python
|
||||
from inference import get_model
|
||||
|
||||
model_id = "<PROJECT_NAME>/<MODEL_VERSION>"
|
||||
model = get_model(model_id=model_id)
|
||||
```
|
||||
|
||||
=== "Ultralytics"
|
||||
|
||||
Similarly to Inference, Ultralytics allows you to run a variety of models.
|
||||
|
||||
```bash
|
||||
pip install "ultralytics<=8.3.40"
|
||||
```
|
||||
|
||||
```python
|
||||
from ultralytics import YOLO
|
||||
|
||||
model = YOLO("yolo11s-seg.pt")
|
||||
```
|
||||
|
||||
## Benchmarking Basics
|
||||
|
||||
Evaluating your model requires careful selection of the dataset. Which images should you use?Let's go over the different scenarios.
|
||||
|
||||
- **Unrelated Dataset**: If you have a dataset that was not used to train the model, this is the best choice.
|
||||
- **Training Set**: This is the set of images used to train the model. This is fine if the model was not trained on this dataset. Otherwise, **never** use it for benchmarking - the results will seem unrealistically good.
|
||||
- **Validation Set**: This is the set of images used to validate the model during training. Every Nth training epoch, the model is evaluated on the validation set. Often the training is stopped once the validation loss stops improving. Therefore, even while the images aren't used to train the model, it still indirectly influences the training outcome.
|
||||
- **Test Set**: This is the set of images kept aside for model testing. It is exactly the set you should use for benchmarking. If the dataset was split correctly, none of these images would be shown to the model during training.
|
||||
|
||||
Therefore, an unrelated dataset or the `test` set is the best choice for benchmarking.
|
||||
Several other problems may arise:
|
||||
|
||||
- **Extra Classes**: An unrelated dataset may contain additional classes which you may need to [filter out](https://supervision.roboflow.com/how_to/filter_detections/#by-set-of-classes) before computing metrics.
|
||||
- **Class Mismatch**: In an unrelated dataset, the class names or IDs may be different to what your model produces, you'll need to remap them, which is [shown in this guide](#running-a-model).
|
||||
- **Data Contamination**: The `test` set may not be split correctly, with images from the test set also present in `training` or `validation` set and used during training. In this case, the results will be overly optimistic. This also applies when **very similar** images are used for training and testing - e.g. those taken in the same environment, same lighting conditions, similar angle, etc.
|
||||
- **Missing Test Set**: Some datasets do not come with a test set. In this case, you should collect and [label](https://roboflow.com/annotate) your own data. Alternatively, a validation set could be used, but the results could be overly optimistic. Make sure to test in the real world as soon as possible.
|
||||
|
||||
## Running a Model
|
||||
|
||||
At this stage, you should have:
|
||||
|
||||
- A dataset of labeled images to evaluate the model.
|
||||
- A model prepared for benchmarking.
|
||||
|
||||
With these ready, we can now run the model and obtain predictions.
|
||||
We'll use `supervision` to create a dataset iterator, and then run the model on each image.
|
||||
|
||||
=== "Inference"
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
test_set = sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=f"{dataset.location}/test/images",
|
||||
annotations_directory_path=f"{dataset.location}/test/labels",
|
||||
data_yaml_path=f"{dataset.location}/data.yaml"
|
||||
)
|
||||
|
||||
image_paths = []
|
||||
predictions_list = []
|
||||
targets_list = []
|
||||
|
||||
for image_path, image, label in test_set:
|
||||
result = model.infer(image)[0]
|
||||
predictions = sv.Detections.from_inference(result)
|
||||
|
||||
image_paths.append(image_path)
|
||||
predictions_list.append(predictions)
|
||||
targets_list.append(label)
|
||||
```
|
||||
|
||||
=== "Ultralytics"
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
test_set = sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=f"{dataset.location}/test/images",
|
||||
annotations_directory_path=f"{dataset.location}/test/labels",
|
||||
data_yaml_path=f"{dataset.location}/data.yaml"
|
||||
)
|
||||
|
||||
image_paths = []
|
||||
predictions_list = []
|
||||
targets_list = []
|
||||
|
||||
for image_path, image, label in test_set:
|
||||
result = model(image)[0]
|
||||
predictions = sv.Detections.from_ultralytics(result)
|
||||
|
||||
image_paths.append(image_path)
|
||||
predictions_list.append(predictions)
|
||||
targets_list.append(label)
|
||||
```
|
||||
|
||||
## Remapping classes
|
||||
|
||||
Did you notice an issue in the above logic?
|
||||
Since we're using an unrelated dataset, the class names and IDs may be different from what the model was trained on.
|
||||
|
||||
We need to remap them to match the dataset classes. Here's how to do it:
|
||||
|
||||
```python
|
||||
def remap_classes(
|
||||
detections: sv.Detections,
|
||||
class_ids_from_to: dict[int, int],
|
||||
class_names_from_to: dict[str, str]
|
||||
) -> None:
|
||||
new_class_ids = [
|
||||
class_ids_from_to.get(class_id, class_id) for class_id in detections.class_id]
|
||||
detections.class_id = np.array(new_class_ids)
|
||||
|
||||
new_class_names = [
|
||||
class_names_from_to.get(name, name) for name in detections["class_name"]]
|
||||
predictions["class_name"] = np.array(new_class_names)
|
||||
```
|
||||
|
||||
Let's also remove the predictions that are not in the dataset classes.
|
||||
|
||||
=== "Inference"
|
||||
|
||||
Dataset class names and IDs can be found in the `data.yaml` file, or by printing `dataset.classes`.
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
test_set = sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=f"{dataset.location}/test/images",
|
||||
annotations_directory_path=f"{dataset.location}/test/labels",
|
||||
data_yaml_path=f"{dataset.location}/data.yaml"
|
||||
)
|
||||
|
||||
image_paths = []
|
||||
predictions_list = []
|
||||
targets_list = []
|
||||
|
||||
for image_path, image, label in test_set:
|
||||
result = model.infer(image)[0]
|
||||
predictions = sv.Detections.from_inference(result)
|
||||
|
||||
remap_classes(
|
||||
detections=predictions,
|
||||
class_ids_from_to={16: 0},
|
||||
class_names_from_to={"dog": "Corgi"}
|
||||
)
|
||||
predictions = predictions[
|
||||
np.isin(predictions["class_name"], test_set.classes)
|
||||
]
|
||||
|
||||
image_paths.append(image_path)
|
||||
predictions_list.append(predictions)
|
||||
targets_list.append(label)
|
||||
```
|
||||
|
||||
=== "Ultralytics"
|
||||
|
||||
Dataset class names and IDs can be found in the `data.yaml` file, or by printing `dataset.classes`.
|
||||
|
||||
Each model will have a different class mapping, so make sure to check the model's documentation. In this case, the model was trained on the COCO dataset, with a class
|
||||
configuration found [here](https://github.com/ultralytics/ultralytics/blob/main/ultralytics/cfg/datasets/coco8.yaml).
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
test_set = sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=f"{dataset.location}/test/images",
|
||||
annotations_directory_path=f"{dataset.location}/test/labels",
|
||||
data_yaml_path=f"{dataset.location}/data.yaml"
|
||||
)
|
||||
|
||||
image_paths = []
|
||||
predictions_list = []
|
||||
targets_list = []
|
||||
|
||||
for image_path, image, label in test_set:
|
||||
result = model(image)[0]
|
||||
predictions = sv.Detections.from_ultralytics(result)
|
||||
|
||||
remap_classes(
|
||||
detections=predictions,
|
||||
class_ids_from_to={16: 0},
|
||||
class_names_from_to={"dog": "Corgi"}
|
||||
)
|
||||
predictions = predictions[
|
||||
np.isin(predictions["class_name"], test_set.classes)
|
||||
]
|
||||
|
||||
image_paths.append(image_path)
|
||||
predictions_list.append(predictions)
|
||||
targets_list.append(label)
|
||||
```
|
||||
|
||||
## Visualizing Predictions
|
||||
|
||||
The first step in evaluating your model’s performance is to visualize its predictions.
|
||||
This gives an intuitive sense of how well your model is detecting objects and where it might be failing.
|
||||
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
N = 9
|
||||
GRID_SIZE = (3, 3)
|
||||
|
||||
target_annotator = sv.PolygonAnnotator(color=sv.Color.from_hex("#8315f9"), thickness=8)
|
||||
prediction_annotator = sv.PolygonAnnotator(color=sv.Color.from_hex("#00cfc6"), thickness=6)
|
||||
|
||||
|
||||
annotated_images = []
|
||||
for image_path, predictions, targets in zip(
|
||||
image_paths[:N], predictions_list[:N], targets_list[:N]
|
||||
):
|
||||
annotated_image = cv2.imread(image_path)
|
||||
annotated_image = target_annotator.annotate(scene=annotated_image, detections=targets)
|
||||
annotated_image = prediction_annotator.annotate(scene=annotated_image, detections=prediction)
|
||||
annotated_images.append(annotated_image)
|
||||
|
||||
sv.plot_images_grid(images=annotated_images, grid_size=GRID_SIZE)
|
||||
```
|
||||
|
||||
Here, predictions in purple are targets (ground truth), and predictions in teal are model predictions.
|
||||
|
||||

|
||||
|
||||
!!! tip
|
||||
|
||||
Use `sv.BoxAnnotator` for object detection and `sv.OrientedBoxAnnotator` for OBB.
|
||||
|
||||
See [annotator documentation](https://supervision.roboflow.com/latest/detection/annotators/) for even more options.
|
||||
|
||||
## Benchmarking Metrics
|
||||
|
||||
With multiple models, fine details matter. Visual inspection may not be enough. `supervision` provides a collection of metrics that help obtain precise numerical results of model performance.
|
||||
|
||||
### Mean Average Precision (mAP)
|
||||
|
||||
We'll start with [MeanAveragePrecision (mAP)](https://supervision.roboflow.com/latest/metrics/mean_average_precision/#supervision.metrics.mean_average_precision.MeanAveragePrecision), which is the most commonly used metric for object detection. It measures the average precision across all classes and IoU thresholds.
|
||||
|
||||
For a thorough explanation, check out our [blog](https://blog.roboflow.com/mean-average-precision/) and [Youtube video](https://www.youtube.com/watch?v=oqXDdxF_Wuw).
|
||||
|
||||
Here, the most popular value is `mAP 50:95`. It represents the average precision across all classes and IoU thresholds (`0.5` to `0.95`), whereas other values such as `mAP 50` or `mAP 75` only consider a single IoU threshold (`0.5` and `0.75` respectively).
|
||||
|
||||
Let's compute the mAP:
|
||||
|
||||
```python
|
||||
from supervision.metrics import MeanAveragePrecision, MetricTarget
|
||||
|
||||
map_metric = MeanAveragePrecision(metric_target=MetricTarget.MASKS)
|
||||
map_result = map_metric.update(predictions_list, targets_list).compute()
|
||||
```
|
||||
|
||||
Try printing the result to see it at a glance:
|
||||
|
||||
```python
|
||||
print(map_result)
|
||||
```
|
||||
|
||||
```
|
||||
MeanAveragePrecisionResult:
|
||||
Metric target: MetricTarget.MASKS
|
||||
Class agnostic: False
|
||||
mAP @ 50:95: 0.2409
|
||||
mAP @ 50: 0.3591
|
||||
mAP @ 75: 0.2915
|
||||
mAP scores: [0.35909 0.3468 0.34556 ...]
|
||||
IoU thresh: [0.5 0.55 0.6 ...]
|
||||
AP per class:
|
||||
0: [0.35909 0.3468 0.34556 ...]
|
||||
...
|
||||
Small objects: ...
|
||||
Medium objects: ...
|
||||
Large objects: ...
|
||||
```
|
||||
|
||||
You can also plot the results:
|
||||
|
||||
```python
|
||||
map_result.plot()
|
||||
```
|
||||
|
||||

|
||||
|
||||
The metric also breaks down the results by detected object area. Small, medium and large are simply those with area less than 32², between 32² and 96², and greater than 96² pixels respectively.
|
||||
|
||||
### F1 Score
|
||||
|
||||
The [F1 Score](https://supervision.roboflow.com/latest/metrics/f1_score/) is another useful metric, especially when dealing with an imbalance between false positives and false negatives. It’s the harmonic mean of **precision** (how many predictions are correct) and **recall** (how many actual instances were detected).
|
||||
|
||||
Here's how you can compute the F1 score:
|
||||
|
||||
```python
|
||||
from supervision.metrics import F1Score, MetricTarget
|
||||
|
||||
f1_metric = F1Score(metric_target=MetricTarget.MASKS)
|
||||
f1_result = f1_metric.update(predictions_list, targets_list).compute()
|
||||
```
|
||||
|
||||
As with mAP, you can also print the result:
|
||||
|
||||
```python
|
||||
print(f1_result)
|
||||
```
|
||||
|
||||
```
|
||||
F1ScoreResult:
|
||||
Metric target: MetricTarget.MASKS
|
||||
Averaging method: AveragingMethod.WEIGHTED
|
||||
F1 @ 50: 0.5341
|
||||
F1 @ 75: 0.4636
|
||||
F1 @ thresh: [0.53406 0.5278 0.52153 ...]
|
||||
IoU thresh: [0.5 0.55 0.6 ...]
|
||||
F1 per class:
|
||||
0: [0.53406 0.5278 0.52153 ...]
|
||||
...
|
||||
Small objects: ...
|
||||
Medium objects: ...
|
||||
Large objects: ...
|
||||
```
|
||||
|
||||
Similarly, you can plot the results:
|
||||
|
||||
```python
|
||||
f1_result.plot()
|
||||
```
|
||||
|
||||

|
||||
|
||||
As with mAP, the metric also breaks down the results by detected object area. Small, medium and large are simply those with area less than 32², between 32² and 96², and greater than 96² pixels respectively.
|
||||
|
||||
## Model Leaderboard
|
||||
|
||||
Here to compare the basic models? We've got you covered. Check out our [Model Leaderboard](https://leaderboard.roboflow.com/) to see how different models perform and to get a sense of the state-of-the-art results. It's a great place to understand what the leading models can achieve and to compare your own results.
|
||||
|
||||
Even better, the repository is open source! You can see how the models were benchmarked, run the evaluation yourself, and even add your own models to the leaderboard. Check it out on [GitHub](https://github.com/roboflow/model-leaderboard)!
|
||||
|
||||

|
||||
|
||||
## Conclusion
|
||||
|
||||
In this guide, you've learned how to set up your environment, train or use pre-trained models, visualize predictions, and evaluate model performance with metrics like [mAP](https://supervision.roboflow.com/latest/metrics/mean_average_precision/), [F1 score](https://supervision.roboflow.com/latest/metrics/f1_score/), and got to know our Model Leaderboard.
|
||||
|
||||
A condensed version of this guide is also available as a [Colab Notebook](https://colab.research.google.com/drive/1HoOY9pZoVwGiRMmLHtir0qT6Uj45w6Ps?usp=sharing).
|
||||
|
||||
For more details, be sure to check out our [documentation](https://supervision.roboflow.com/latest/) and join our community discussions. If you find any issues, please let us know on [GitHub](https://github.com/roboflow/supervision/issues).
|
||||
|
||||
Best of luck with your benchmarking!
|
||||
|
|
@ -55,7 +55,7 @@ it will be modified to include tracking, labeling, and trace annotations.
|
|||
from ultralytics import YOLO
|
||||
|
||||
model = YOLO("yolov8n.pt")
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
|
||||
def callback(frame: np.ndarray, _: int) -> np.ndarray:
|
||||
results = model(frame)[0]
|
||||
|
|
@ -77,7 +77,7 @@ it will be modified to include tracking, labeling, and trace annotations.
|
|||
from inference.models.utils import get_roboflow_model
|
||||
|
||||
model = get_roboflow_model(model_id="yolov8n-640", api_key=<ROBOFLOW API KEY>)
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
|
||||
def callback(frame: np.ndarray, _: int) -> np.ndarray:
|
||||
results = model.infer(frame)[0]
|
||||
|
|
@ -112,7 +112,7 @@ enabling the continuous following of the object's motion path across different f
|
|||
|
||||
model = YOLO("yolov8n.pt")
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
|
||||
def callback(frame: np.ndarray, _: int) -> np.ndarray:
|
||||
results = model(frame)[0]
|
||||
|
|
@ -136,7 +136,7 @@ enabling the continuous following of the object's motion path across different f
|
|||
|
||||
model = get_roboflow_model(model_id="yolov8n-640", api_key=<ROBOFLOW API KEY>)
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
|
||||
def callback(frame: np.ndarray, _: int) -> np.ndarray:
|
||||
results = model.infer(frame)[0]
|
||||
|
|
@ -168,7 +168,7 @@ offering a clear visual representation of each object's class and unique identif
|
|||
|
||||
model = YOLO("yolov8n.pt")
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
label_annotator = sv.LabelAnnotator()
|
||||
|
||||
def callback(frame: np.ndarray, _: int) -> np.ndarray:
|
||||
|
|
@ -177,9 +177,9 @@ offering a clear visual representation of each object's class and unique identif
|
|||
detections = tracker.update_with_detections(detections)
|
||||
|
||||
labels = [
|
||||
f"#{tracker_id} {results.names[class_id]}"
|
||||
for class_id, tracker_id
|
||||
in zip(detections.class_id, detections.tracker_id)
|
||||
f"#{tracker_id} {class_name}"
|
||||
for class_name, tracker_id
|
||||
in zip(detections.data["class_name"], detections.tracker_id)
|
||||
]
|
||||
|
||||
annotated_frame = box_annotator.annotate(
|
||||
|
|
@ -203,7 +203,7 @@ offering a clear visual representation of each object's class and unique identif
|
|||
|
||||
model = get_roboflow_model(model_id="yolov8n-640", api_key=<ROBOFLOW API KEY>)
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
label_annotator = sv.LabelAnnotator()
|
||||
|
||||
def callback(frame: np.ndarray, _: int) -> np.ndarray:
|
||||
|
|
@ -212,9 +212,9 @@ offering a clear visual representation of each object's class and unique identif
|
|||
detections = tracker.update_with_detections(detections)
|
||||
|
||||
labels = [
|
||||
f"#{tracker_id} {results.names[class_id]}"
|
||||
for class_id, tracker_id
|
||||
in zip(detections.class_id, detections.tracker_id)
|
||||
f"#{tracker_id} {class_name}"
|
||||
for class_name, tracker_id
|
||||
in zip(detections.data["class_name"], detections.tracker_id)
|
||||
]
|
||||
|
||||
annotated_frame = box_annotator.annotate(
|
||||
|
|
@ -250,7 +250,7 @@ movement patterns and interactions between objects in the video.
|
|||
|
||||
model = YOLO("yolov8n.pt")
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
label_annotator = sv.LabelAnnotator()
|
||||
trace_annotator = sv.TraceAnnotator()
|
||||
|
||||
|
|
@ -260,9 +260,9 @@ movement patterns and interactions between objects in the video.
|
|||
detections = tracker.update_with_detections(detections)
|
||||
|
||||
labels = [
|
||||
f"#{tracker_id} {results.names[class_id]}"
|
||||
for class_id, tracker_id
|
||||
in zip(detections.class_id, detections.tracker_id)
|
||||
f"#{tracker_id} {class_name}"
|
||||
for class_name, tracker_id
|
||||
in zip(detections.data["class_name"], detections.tracker_id)
|
||||
]
|
||||
|
||||
annotated_frame = box_annotator.annotate(
|
||||
|
|
@ -288,7 +288,7 @@ movement patterns and interactions between objects in the video.
|
|||
|
||||
model = get_roboflow_model(model_id="yolov8n-640", api_key=<ROBOFLOW API KEY>)
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
label_annotator = sv.LabelAnnotator()
|
||||
trace_annotator = sv.TraceAnnotator()
|
||||
|
||||
|
|
@ -298,9 +298,9 @@ movement patterns and interactions between objects in the video.
|
|||
detections = tracker.update_with_detections(detections)
|
||||
|
||||
labels = [
|
||||
f"#{tracker_id} {results.names[class_id]}"
|
||||
for class_id, tracker_id
|
||||
in zip(detections.class_id, detections.tracker_id)
|
||||
f"#{tracker_id} {class_name}"
|
||||
for class_name, tracker_id
|
||||
in zip(detections.data["class_name"], detections.tracker_id)
|
||||
]
|
||||
|
||||
annotated_frame = box_annotator.annotate(
|
||||
|
|
|
|||
|
|
@ -10,13 +10,19 @@ hide:
|
|||
<h1></h1>
|
||||
</div>
|
||||
|
||||
<div align="center" id="logo">
|
||||
<div align="center" id="logo" style="padding-top: 1rem;">
|
||||
<a align="center" href="" target="_blank">
|
||||
<img width="850"
|
||||
src="https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png?updatedAt=1678995927529">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#hello {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
## 👋 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!
|
||||
|
|
@ -31,10 +37,11 @@ We write your reusable computer vision tools. Whether you need to load your data
|
|||
## 💻 Install
|
||||
|
||||
You can install `supervision` in a
|
||||
[**Python>=3.8**](https://www.python.org/) environment.
|
||||
[**Python>=3.9**](https://www.python.org/) environment.
|
||||
|
||||
!!! example "pip install (recommended)"
|
||||
=== "pip"
|
||||
!!! example "Installation"
|
||||
|
||||
=== "pip (recommended)"
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
[](https://pypistats.org/packages/supervision)
|
||||
[](https://github.com/roboflow/supervision/blob/main/LICENSE.md)
|
||||
|
|
@ -44,6 +51,43 @@ You can install `supervision` in a
|
|||
pip install supervision
|
||||
```
|
||||
|
||||
=== "poetry"
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
[](https://pypistats.org/packages/supervision)
|
||||
[](https://github.com/roboflow/supervision/blob/main/LICENSE.md)
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
|
||||
```bash
|
||||
poetry add supervision
|
||||
```
|
||||
|
||||
=== "uv"
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
[](https://pypistats.org/packages/supervision)
|
||||
[](https://github.com/roboflow/supervision/blob/main/LICENSE.md)
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
|
||||
```bash
|
||||
uv pip install supervision
|
||||
```
|
||||
|
||||
For uv projects:
|
||||
|
||||
```bash
|
||||
uv add supervision
|
||||
```
|
||||
|
||||
=== "rye"
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
[](https://pypistats.org/packages/supervision)
|
||||
[](https://github.com/roboflow/supervision/blob/main/LICENSE.md)
|
||||
[](https://badge.fury.io/py/supervision)
|
||||
|
||||
```bash
|
||||
rye add supervision
|
||||
```
|
||||
|
||||
|
||||
!!! example "conda/mamba install"
|
||||
=== "conda"
|
||||
[](https://anaconda.org/conda-forge/supervision) [](https://anaconda.org/conda-forge/supervision) [](https://anaconda.org/conda-forge/supervision) [](https://anaconda.org/conda-forge/supervision)
|
||||
|
|
@ -63,7 +107,7 @@ You can install `supervision` in a
|
|||
=== "virtualenv"
|
||||
```bash
|
||||
# clone repository and navigate to root directory
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision
|
||||
|
||||
# setup python environment and activate it
|
||||
|
|
@ -75,18 +119,19 @@ You can install `supervision` in a
|
|||
pip install -e "."
|
||||
```
|
||||
|
||||
=== "poetry"
|
||||
=== "uv"
|
||||
```bash
|
||||
# clone repository and navigate to root directory
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision
|
||||
|
||||
# setup python environment and activate it
|
||||
poetry env use python3.10
|
||||
poetry shell
|
||||
uv venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# installation
|
||||
poetry install
|
||||
uv pip install -r pyproject.toml -e . --all-extras
|
||||
|
||||
```
|
||||
|
||||
## 🚀 Quickstart
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
<div
|
||||
class="author-container"
|
||||
data-login="${authorData.login}-${elementIndex}"
|
||||
style="margin-left: ${marginLeft}; z-index: ${zIndex};"
|
||||
style="margin-left: ${marginLeft};"
|
||||
>
|
||||
<a
|
||||
href="https://github.com/${authorData.login}"
|
||||
|
|
@ -90,14 +90,17 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
).join(', ');
|
||||
|
||||
let authorsHTML = `
|
||||
<div class="authors">
|
||||
<div class="authors" style="margin: 0;">
|
||||
${authorAvatarsHTML}
|
||||
<div class="author-names">${authorNamesHTML}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
element.innerText = `
|
||||
<div style="flex-direction: column; height: 100%; display: flex;
|
||||
<div style="
|
||||
display: grid !important;
|
||||
grid-template-rows: auto;
|
||||
height: 100%;
|
||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji; background: ${theme.background}; font-size: 14px; line-height: 1.5; color: ${theme.color}">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<span style="font-weight: 700; font-size: 1rem; color: ${theme.linkColor};">
|
||||
|
|
@ -105,13 +108,14 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
</span>
|
||||
</div>
|
||||
${authorsHTML}
|
||||
<div style="font-size: 12px; color: ${theme.color}; display: flex; flex: 0; justify-content: space-between">
|
||||
<div style="font-size: 12px; color: ${theme.color}; display: grid; grid-template-columns: auto 3fr; justify-content: space-between; gap: 1rem;">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="/assets/supervision-lenny.png" aria-label="stars" width="20" height="20" role="img" />
|
||||
|
||||
<span style="margin-left: 4px">${version}</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; flex-wrap: wrap">
|
||||
<div style="display: flex; align-items: center; flex-wrap: wrap; align-content: right;
|
||||
gap: 0.1rem;">
|
||||
${labelHTML}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
window.MathJax = {
|
||||
tex: {
|
||||
inlineMath: [["\\(", "\\)"]],
|
||||
displayMath: [["\\[", "\\]"]],
|
||||
processEscapes: true,
|
||||
processEnvironments: true
|
||||
},
|
||||
options: {
|
||||
ignoreHtmlClass: ".*|",
|
||||
processHtmlClass: "arithmatex"
|
||||
}
|
||||
};
|
||||
|
||||
document$.subscribe(() => {
|
||||
MathJax.startup.output.clearCache()
|
||||
MathJax.typesetClear()
|
||||
MathJax.texReset()
|
||||
MathJax.typesetPromise()
|
||||
})
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
!function(){var i="analytics",analytics=window[i]=window[i]||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","screen","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware","register"];analytics.factory=function(e){return function(){if(window[i].initialized)return window[i][e].apply(window[i],arguments);var n=Array.prototype.slice.call(arguments);if(["track","screen","alias","group","page","identify"].indexOf(e)>-1){var c=document.querySelector("link[rel='canonical']");n.push({__t:"bpc",c:c&&c.getAttribute("href")||void 0,p:location.pathname,u:location.href,s:location.search,t:document.title,r:document.referrer})}n.unshift(e);analytics.push(n);return analytics}};for(var n=0;n<analytics.methods.length;n++){var key=analytics.methods[n];analytics[key]=analytics.factory(key)}analytics.load=function(key,n){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute("data-global-segment-analytics-key",i);t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r);analytics._loadOptions=n};analytics._writeKey="rMvrPeZBJYyOPJSGCNhMlnTJb8VhFiWU";;analytics.SNIPPET_VERSION="5.2.0";
|
||||
analytics.load("eohFog7VZiAhGJGEr5Sh7BM1mFKmUvDC");
|
||||
document$.subscribe(analytics.page);
|
||||
}}();
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Annotators
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Common Values
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# F1 Score
|
||||
|
|
|
|||
|
|
@ -16,3 +16,9 @@ status: new
|
|||
</div>
|
||||
|
||||
:::supervision.metrics.mean_average_precision.MeanAveragePrecisionResult
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.dataset.formats.coco.get_coco_class_index_mapping">get_coco_class_index_mapping</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.dataset.formats.coco.get_coco_class_index_mapping
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Mean Average Recall
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Precision
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# Recall
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q inference-gpu \"supervision[assets]\""
|
||||
"!pip install -q inference-gpu \"supervision\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
|
|
@ -207,7 +207,6 @@
|
|||
],
|
||||
"source": [
|
||||
"import supervision as sv\n",
|
||||
"from supervision.assets import download_assets, VideoAssets\n",
|
||||
"from inference.models.utils import get_roboflow_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -17,7 +17,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "shellscript"
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q \"supervision[assets]\""
|
||||
"pip install -q \"supervision\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q torch diffusers accelerate inference-gpu[yolo-world] dill git+https://github.com/openai/CLIP.git supervision==0.19.0rc5"
|
||||
"!pip install -q torch diffusers accelerate inference-gpu[yolo-world] dill git+https://github.com/openai/CLIP.git supervision"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q inference-gpu \"supervision[assets]\""
|
||||
"!pip install -q inference-gpu \"supervision\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install roboflow supervision==0.19.0 -q"
|
||||
"!pip install roboflow supervision -q"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -495,7 +495,7 @@
|
|||
"source": [
|
||||
"from ultralytics import YOLO\n",
|
||||
"\n",
|
||||
"model = YOLO(\"yolov8x.pt\")\n",
|
||||
"model = YOLO(\"yolo11x.pt\")\n",
|
||||
"result = model(image, verbose=False)[0]\n",
|
||||
"detections = sv.Detections.from_ultralytics(result)"
|
||||
]
|
||||
|
|
@ -594,7 +594,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 33,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "yM6dmicTRGl6"
|
||||
},
|
||||
|
|
@ -602,7 +602,7 @@
|
|||
"source": [
|
||||
"from ultralytics import YOLO\n",
|
||||
"\n",
|
||||
"model = YOLO(\"yolov8x-seg.pt\")\n",
|
||||
"model = YOLO(\"yolo11x-seg.pt\")\n",
|
||||
"result = model(image, verbose=False)[0]\n",
|
||||
"detections = sv.Detections.from_ultralytics(result)"
|
||||
]
|
||||
|
|
@ -926,7 +926,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q supervision[assets]"
|
||||
"!pip install -q supervision"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -32,7 +32,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q inference requests tqdm supervision==0.21.0"
|
||||
"!pip install -q inference requests tqdm supervision"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,12 +695,12 @@
|
|||
"source": [
|
||||
"###\u00a0Annotate Image with Detections\n",
|
||||
"\n",
|
||||
"Finally, we can annotate the image with the predictions. Since we are working with an object detection model, we will use the [`sv.BoundingBoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoundingBoxAnnotator) and [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.LabelAnnotator) classes."
|
||||
"Finally, we can annotate the image with the predictions. Since we are working with an object detection model, we will use the [`sv.BoxAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.BoxAnnotator) and [`sv.LabelAnnotator`](https://supervision.roboflow.com/latest/detection/annotators/#supervision.annotators.core.LabelAnnotator) classes."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 49,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
|
|
@ -722,7 +722,7 @@
|
|||
}
|
||||
],
|
||||
"source": [
|
||||
"bounding_box_annotator = sv.BoundingBoxAnnotator()\n",
|
||||
"bounding_box_annotator = sv.BoxAnnotator()\n",
|
||||
"label_annotator = sv.LabelAnnotator()\n",
|
||||
"\n",
|
||||
"annotated_frame = frame.copy()\n",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
/* Large screens (1024px and up) */
|
||||
@media (min-width: 1024px) {
|
||||
.custom-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
:root {
|
||||
:root, body {
|
||||
/* Default to light theme */
|
||||
--md-primary-fg-color: #8315F9;
|
||||
--md-accent-fg-color: #00FFCE;
|
||||
--md-code-hl-color: #8315F9 !important;
|
||||
--md-accent-fg-color: #8315F9 !important;
|
||||
--md-code-hl-color--light: #e8d2ff89 !important;
|
||||
--md-footer-fg-color--light: rgb(111, 108, 121) !important;
|
||||
}
|
||||
|
||||
body.light {
|
||||
|
|
@ -9,6 +12,202 @@ body.light {
|
|||
--md-text-color: #000000;
|
||||
--md-h2-color: #000000;
|
||||
}
|
||||
.md-grid {
|
||||
max-width: 85%;
|
||||
margin: auto;
|
||||
}
|
||||
.sublist {
|
||||
display: none;
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
background: white;
|
||||
position: absolute;
|
||||
border-radius: 8px;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.sublist {
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
display: none;
|
||||
position: absolute; /* Ensure it overlaps and doesn't break flow */
|
||||
background: white; /* So it's visible */
|
||||
z-index: 1000;
|
||||
}
|
||||
.sublist li {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
#products-list *:hover .products-sublist {
|
||||
display: block;
|
||||
}
|
||||
#resources-list *, #products-list * {
|
||||
cursor: pointer;
|
||||
}
|
||||
.products-sublist, .resources-sublist {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
.products-sublist li:hover, .resources-sublist li:hover, .md-nav__link[href]:hover {
|
||||
background: rgb(242, 241, 247) !important;
|
||||
border-radius: 6px;
|
||||
color: initial !important;
|
||||
}
|
||||
.md-search {
|
||||
flex-grow: 2;
|
||||
}
|
||||
.portfolio-section .md-grid {
|
||||
max-width: 100%;
|
||||
}
|
||||
.md-header__inner {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: 0.1fr 1.4fr 2fr 2fr;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
.md-search__inner {
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
.md-search__input {
|
||||
background: white;
|
||||
border: 1px solid rgb(229, 231, 235);
|
||||
border-radius: 8px;
|
||||
color: rgb(111, 108, 121);
|
||||
}
|
||||
.md-search__form *, .md-search__icon, .md-search__input {
|
||||
color: rgb(111, 108, 121);
|
||||
}
|
||||
.md-search__input::placeholder {
|
||||
color: rgb(156, 163, 175);
|
||||
}
|
||||
.md-search__form {
|
||||
background: none !important;
|
||||
}
|
||||
.md-footer, .md-footer-meta {
|
||||
background-color: transparent;
|
||||
color: rgb(111, 108, 121);
|
||||
}
|
||||
.md-typeset .tabbed-set > input:first-child:checked ~ .tabbed-labels > :first-child, .md-typeset .tabbed-set > input:nth-child(10):checked ~ .tabbed-labels > :nth-child(10), .md-typeset .tabbed-set > input:nth-child(11):checked ~ .tabbed-labels > :nth-child(11), .md-typeset .tabbed-set > input:nth-child(12):checked ~ .tabbed-labels > :nth-child(12), .md-typeset .tabbed-set > input:nth-child(13):checked ~ .tabbed-labels > :nth-child(13), .md-typeset .tabbed-set > input:nth-child(14):checked ~ .tabbed-labels > :nth-child(14), .md-typeset .tabbed-set > input:nth-child(15):checked ~ .tabbed-labels > :nth-child(15), .md-typeset .tabbed-set > input:nth-child(16):checked ~ .tabbed-labels > :nth-child(16), .md-typeset .tabbed-set > input:nth-child(17):checked ~ .tabbed-labels > :nth-child(17), .md-typeset .tabbed-set > input:nth-child(18):checked ~ .tabbed-labels > :nth-child(18), .md-typeset .tabbed-set > input:nth-child(19):checked ~ .tabbed-labels > :nth-child(19), .md-typeset .tabbed-set > input:nth-child(2):checked ~ .tabbed-labels > :nth-child(2), .md-typeset .tabbed-set > input:nth-child(20):checked ~ .tabbed-labels > :nth-child(20), .md-typeset .tabbed-set > input:nth-child(3):checked ~ .tabbed-labels > :nth-child(3), .md-typeset .tabbed-set > input:nth-child(4):checked ~ .tabbed-labels > :nth-child(4), .md-typeset .tabbed-set > input:nth-child(5):checked ~ .tabbed-labels > :nth-child(5), .md-typeset .tabbed-set > input:nth-child(6):checked ~ .tabbed-labels > :nth-child(6), .md-typeset .tabbed-set > input:nth-child(7):checked ~ .tabbed-labels > :nth-child(7), .md-typeset .tabbed-set > input:nth-child(8):checked ~ .tabbed-labels > :nth-child(8), .md-typeset .tabbed-set > input:nth-child(9):checked ~ .tabbed-labels > :nth-child(9) {
|
||||
color: #8315F9;
|
||||
border-bottom: 1px solid #8315F9;
|
||||
}
|
||||
.md-footer *, html .md-footer-meta.md-typeset a {
|
||||
color: rgb(111, 108, 121);
|
||||
}
|
||||
.repo-card {
|
||||
height: 100%;
|
||||
}
|
||||
.header-btn {
|
||||
text-align: center;
|
||||
}
|
||||
.header-btn, .sublist {
|
||||
box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px, rgb(217, 215, 226) 0px 0px 0px 1px, rgb(217, 215, 226) 0px 1px 2px 0px;
|
||||
}
|
||||
.header-btn:hover {
|
||||
box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px, rgb(217, 215, 226) 0px 0px 0px 1px, rgb(217, 215, 226) 0px 1.0001px 2.00013px -0.0000327245px, rgba(0, 0, 0, 0) 0px 0.000065449px 0.000130898px -0.000065449px;
|
||||
}
|
||||
.md-typeset .headerlink:hover, .md-typeset .headerlink:target {
|
||||
color: #8315F9;
|
||||
}
|
||||
.md-typeset h1, .md-header__title {
|
||||
color: black;
|
||||
font-weight: 800;
|
||||
}
|
||||
.md-typeset h1 {
|
||||
font-weight: normal;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
body {
|
||||
background: linear-gradient(to left bottom, rgb(243, 238, 255), rgb(255, 255, 255) 60%) no-repeat;
|
||||
}
|
||||
|
||||
/* .md-nav__link:has([tabindex=""]) {
|
||||
text-transform: uppercase;
|
||||
} */
|
||||
|
||||
.header-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
list-style: none;
|
||||
font-size: 0.75rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.md-nav__list label, .md-nav--secondary label {
|
||||
/* text-transform: uppercase; */
|
||||
color: rgb(29, 29, 31) !important;
|
||||
font-size: 0.7rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.md-nav--secondary label {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.md-nav__link {
|
||||
padding: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.md-nav__link--active {
|
||||
background: rgb(243, 238, 255);
|
||||
border-radius: 6px;
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
.md-tabs__item--active {
|
||||
color: var(--md-primary-fg-color);
|
||||
border-bottom: 2px solid var(--md-primary-fg-color);
|
||||
}
|
||||
|
||||
.md-nav--secondary .md-nav__title {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.md-header, .md-tabs {
|
||||
color: rgb(111, 108, 121);
|
||||
background-color: transparent;
|
||||
}
|
||||
.md-header--shadow {
|
||||
background: linear-gradient(to left bottom, rgb(243, 238, 255), rgb(255, 255, 255) 60%);
|
||||
box-shadow: none;
|
||||
border-bottom: 1px solid rgb(229, 231, 235);
|
||||
}
|
||||
|
||||
#item-logo {
|
||||
display: none;
|
||||
}
|
||||
.md-main__inner, .md-header__inner, .md-grid {
|
||||
max-width: 100%;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.md-header__inner {
|
||||
display: flex;
|
||||
}
|
||||
.header-list {
|
||||
display: none;
|
||||
}
|
||||
#item-logo {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.md-content {
|
||||
max-width: 40rem;
|
||||
margin: auto;
|
||||
}
|
||||
/* // if no md-sidebar--primary, make .md-content full width */
|
||||
.md-main__inner:has(.md-sidebar--primary[hidden]) .md-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
.md-sidebar--primary {
|
||||
flex: 0 20%;
|
||||
}
|
||||
.md-tabs {
|
||||
border-bottom: 1px solid rgb(229, 231, 235);
|
||||
}
|
||||
.md-main__inner {
|
||||
padding-top: 1rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
body.dark {
|
||||
/* Dark theme */
|
||||
|
|
@ -29,3 +228,43 @@ body[data-md-url$="/cookbooks/"] .md-content {
|
|||
margin-left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.md-main, nav .md-grid, .md-header__inner {
|
||||
max-width: 1600px;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.md-search__scrollwrap {
|
||||
width: 100% !important;
|
||||
}
|
||||
.md-nav--secondary .md-nav__title {
|
||||
position: initial !important;
|
||||
}
|
||||
|
||||
.md-header__title .md-ellipsis {
|
||||
overflow: initial !important;
|
||||
text-overflow: initial !important;
|
||||
}
|
||||
.md-search {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
/* Table style */
|
||||
|
||||
th, td {
|
||||
border: 1px solid var(--md-typeset-table-color);
|
||||
}
|
||||
|
||||
.md-typeset__table {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.md-typeset__table table:not([class]) {
|
||||
font-size: 0.6rem;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.md-typeset__table table:not([class]) td,
|
||||
.md-typeset__table table:not([class]) th {
|
||||
padding: 10px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@
|
|||
</div>
|
||||
<div class="custom-grid">
|
||||
<a href="/develop/notebooks/quickstart"> <p class="card repo-card" data-name="Supervision Quickstart" data-labels="ANNOTATOR,DETECTION,SAM"
|
||||
data-version="v0.18.0" data-author="SkalskiP,onuralpszr"></p>
|
||||
data-version="v0.26.0" data-author="SkalskiP,onuralpszr"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/count-objects-crossing-the-line">
|
||||
<p class="card repo-card" data-name="Count Objects Crossing the Line"
|
||||
data-labels="ANNOTATORS,LINE ZONE,TRACKING" data-version="v0.18.0" data-author="SkalskiP"></p>
|
||||
data-labels="ANNOTATORS,LINE ZONE,TRACKING" data-version="v0.26.0" data-author="SkalskiP"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/zero-shot-object-detection-with-yolo-world">
|
||||
<p class="card repo-card" data-name="Zero-Shot Object Detection with YOLO-World"
|
||||
data-labels="ANNOTATORS,DETECTION,INFERENCE" data-version="v0.19.0" data-author="SkalskiP"></p>
|
||||
data-labels="ANNOTATORS,DETECTION,INFERENCE" data-version="v0.26.0" data-author="SkalskiP"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/download-supervision-assets">
|
||||
<p class="card repo-card" data-name="Downloading Supervision Assets" data-labels="ASSETS" data-version="v0.18.0"
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
</a>
|
||||
<a href="/develop/notebooks/annotate-video-with-detections">
|
||||
<p class="card repo-card" data-name="Annotate Video with Detections" data-labels="INFERENCE,YOLOV8"
|
||||
data-version="v0.18.0" data-author="nickherrig"></p>
|
||||
data-version="v0.26.0" data-author="nickherrig"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/object-tracking">
|
||||
<p class="card repo-card" data-name="Object Tracking" data-labels="TRACKING, ANNOTATOR" data-version="v0.18.0"
|
||||
|
|
@ -36,23 +36,23 @@
|
|||
</a>
|
||||
<a href="/develop/notebooks/occupancy_analytics">
|
||||
<p class="card repo-card" data-name="Analyzing Zone Occupancy" data-labels="ANNOTATOR,DETECTION,ZONES"
|
||||
data-version="v0.19.0" data-author="stellasphere"></p>
|
||||
data-version="v0.26.0" data-author="stellasphere"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/evaluating-alignment-of-text-to-image-diffusion-models">
|
||||
<p class="card repo-card" data-name="Evaluating Alignment of Text-to-image Diffusion Models"
|
||||
data-labels="ANNOTATORS,YOLO WORLD" data-version="v0.19.0rc5" data-author="iamhatesz"></p>
|
||||
data-labels="ANNOTATORS,YOLO WORLD" data-version="v0.26.0" data-author="iamhatesz"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/serialise-detections-to-csv">
|
||||
<p class="card repo-card" data-name="Serialise Detections to a CSV File"
|
||||
data-labels="DETECTIONS,CSV SINK,INFERENCE" data-version="v0.21.0" data-author="onuralpszr"></p>
|
||||
data-labels="DETECTIONS,CSV SINK,INFERENCE" data-version="v0.26.0" data-author="onuralpszr"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/serialise-detections-to-json">
|
||||
<p class="card repo-card" data-name="Serialise Detections to a JSON File"
|
||||
data-labels="DETECTIONS,JSON SINK,INFERENCE" data-version="v0.21.0" data-author="onuralpszr"></p>
|
||||
data-labels="DETECTIONS,JSON SINK,INFERENCE" data-version="v0.26.0" data-author="onuralpszr"></p>
|
||||
</a>
|
||||
<a href="/develop/notebooks/small-object-detection-with-sahi">
|
||||
<p class="card repo-card" data-name="Small Object Detection with SAHI"
|
||||
data-labels="DETECTIONS,SAHI,SMALL,OBJECT,INFERENCE" data-version="v0.23.0" data-author="ediardo"></p>
|
||||
data-labels="DETECTIONS,SAHI,SMALL,OBJECT,INFERENCE" data-version="v0.26.0" data-author="ediardo"></p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,181 @@
|
|||
{% set class = "md-header" %}
|
||||
{% if "navigation.tabs.sticky" in features %}
|
||||
{% set class = class ~ " md-header--shadow md-header--lifted" %}
|
||||
{% elif "navigation.tabs" not in features %}
|
||||
{% set class = class ~ " md-header--shadow" %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Header -->
|
||||
<header class="{{ class }}" data-md-component="header">
|
||||
<nav
|
||||
class="md-header__inner md-grid"
|
||||
aria-label="{{ lang.t('header') }}"
|
||||
>
|
||||
|
||||
<!-- Link to home -->
|
||||
<a
|
||||
href="{{ config.extra.homepage | d(nav.homepage.url, true) | url }}"
|
||||
title="{{ config.site_name | e }}"
|
||||
class="md-header__button md-logo"
|
||||
aria-label="{{ config.site_name }}"
|
||||
data-md-component="logo"
|
||||
>
|
||||
{% include "partials/logo.html" %}
|
||||
</a>
|
||||
|
||||
<!-- Button to open drawer -->
|
||||
<label class="md-header__button md-icon" for="__drawer">
|
||||
{% set icon = config.theme.icon.menu or "material/menu" %}
|
||||
{% include ".icons/" ~ icon ~ ".svg" %}
|
||||
</label>
|
||||
|
||||
<!-- Header title -->
|
||||
<div class="md-header__title" data-md-component="header-title">
|
||||
<div class="md-header__ellipsis">
|
||||
<div class="md-header__topic">
|
||||
<span class="md-ellipsis">
|
||||
{{ config.site_name }} Docs
|
||||
</span>
|
||||
</div>
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis" style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<a
|
||||
href="{{ config.extra.homepage | d(nav.homepage.url, true) | url }}"
|
||||
title="{{ config.site_name | e }}"
|
||||
class="md-header__button md-logo"
|
||||
aria-label="{{ config.site_name }}"
|
||||
data-md-component="logo"
|
||||
id="item-logo"
|
||||
>
|
||||
{% include "partials/logo.html" %}
|
||||
</a>
|
||||
{% if page.meta and page.meta.title %}
|
||||
{{ page.meta.title }}
|
||||
{% else %}
|
||||
{{ page.title }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Button to open search modal -->
|
||||
{% if "material/search" in config.plugins %}
|
||||
{% set search = config.plugins["material/search"] | attr("config") %}
|
||||
|
||||
<!-- Check if search is actually enabled - see https://t.ly/DT_0V -->
|
||||
{% if search.enabled %}
|
||||
<label class="md-header__button md-icon" for="__search">
|
||||
{% set icon = config.theme.icon.search or "material/magnify" %}
|
||||
{% include ".icons/" ~ icon ~ ".svg" %}
|
||||
</label>
|
||||
|
||||
<!-- Search interface -->
|
||||
{% include "partials/search.html" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<ul class="header-list">
|
||||
<li style="align-items: center;" id="resources-list">
|
||||
<label for="dropdown-resources"><span>Resources <img src="https://ka-p.fontawesome.com/releases/v6.6.0/svgs/regular/chevron-down.svg?v=2&token=a463935e93" style="height: 0.5rem;" /></span></label>
|
||||
<input type="radio" name="dropdown" id="dropdown-resources" style="display: none;" />
|
||||
<ul class="resources-sublist sublist">
|
||||
<li><a href="https://blog.roboflow.com">Blog</a></li>
|
||||
<li><a href="https://discuss.roboflow.com">Community Forum</a></li>
|
||||
<li><a href="https://roboflow.com/sales">Contact Sales</a></li>
|
||||
<li><a href="https://universe.roboflow.com">Universe</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li style="align-items: center;" id="products-list">
|
||||
<label for="dropdown-products"><span>Docs <img src="https://ka-p.fontawesome.com/releases/v6.6.0/svgs/regular/chevron-down.svg?v=2&token=a463935e93" style="height: 0.5rem;" /></span></label>
|
||||
<input type="radio" name="dropdown" id="dropdown-products" style="display: none;" />
|
||||
<ul class="products-sublist sublist">
|
||||
<li><a href="https://inference.roboflow.com">Inference</a></li>
|
||||
<li><a href="https://supervision.roboflow.com">Supervision</a></li>
|
||||
<li><a href="https://trackers.roboflow.com">Trackers</a></li>
|
||||
<li><a href="https://maestro.roboflow.com">Maestro</a></li>
|
||||
<li><a href="https://docs.roboflow.com">Roboflow</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<script>
|
||||
document.addEventListener('click', function(event) {
|
||||
const resourcesList = document.getElementById('resources-list');
|
||||
const productsList = document.getElementById('products-list');
|
||||
const dropdownResources = document.getElementById('dropdown-resources');
|
||||
const dropdownProducts = document.getElementById('dropdown-products');
|
||||
|
||||
if (!resourcesList.contains(event.target)) {
|
||||
dropdownResources.checked = false;
|
||||
}
|
||||
if (!productsList.contains(event.target)) {
|
||||
dropdownProducts.checked = false;
|
||||
}
|
||||
});
|
||||
// on mouse over
|
||||
document.getElementById('resources-list').addEventListener('mouseover', function() {
|
||||
document.getElementById('dropdown-resources').checked = true;
|
||||
});
|
||||
document.getElementById('products-list').addEventListener('mouseover', function() {
|
||||
document.getElementById('dropdown-products').checked = true;
|
||||
});
|
||||
// on mouse out
|
||||
document.getElementById('resources-list').addEventListener('mouseout', function() {
|
||||
// if not hovering over the sublist or the label, uncheck the dropdown
|
||||
// wait 1 sec
|
||||
setTimeout(function() {
|
||||
if (!document.querySelector('.resources-sublist:hover') && !document.querySelector('#resources-list:hover')) {
|
||||
document.getElementById('dropdown-resources').checked = false;
|
||||
}
|
||||
}, 350);
|
||||
});
|
||||
// if mouseout of sublist, uncheck immediately
|
||||
document.querySelector('.resources-sublist').addEventListener('mouseout', function() {
|
||||
setTimeout(function() {
|
||||
if (!document.querySelector('.resources-sublist:hover') && !document.querySelector('#resources-list:hover')) {
|
||||
document.getElementById('dropdown-resources').checked = false;
|
||||
}
|
||||
}, 450);
|
||||
});
|
||||
document.getElementById('products-list').addEventListener('mouseout', function() {
|
||||
// if not hovering over the sublist, uncheck the dropdown
|
||||
// wait 1 sec
|
||||
setTimeout(function() {
|
||||
if (!document.querySelector('.products-sublist:hover') && !document.querySelector('#products-list:hover')) {
|
||||
document.getElementById('dropdown-products').checked = false;
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
// if mouseout of sublist, uncheck immediately
|
||||
document.querySelector('.products-sublist').addEventListener('mouseout', function() {
|
||||
setTimeout(function() {
|
||||
if (!document.querySelector('.products-sublist:hover') && !document.querySelector('#products-list:hover')) {
|
||||
document.getElementById('dropdown-products').checked = false;
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#dropdown-resources:checked ~ .resources-sublist {
|
||||
display: block;
|
||||
}
|
||||
#dropdown-products:checked ~ .products-sublist {
|
||||
display: block;
|
||||
}
|
||||
/* Hide dropdown if clicking outside */
|
||||
body:not(:has(#dropdown-resources:checked)) .resources-sublist,
|
||||
body:not(:has(#dropdown-products:checked)) .products-sublist {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<a href="https://github.com/roboflow/supervision"><li class="header-btn" style="border-radius: 5px; color: white; background: var(--md-typeset-a-color); padding-top: 0.25rem; padding-left: 0.5rem; padding-bottom: 0.25rem; padding-right: 0.5rem; border: 1px solid #8315F9;">Go to GitHub</li></a>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Navigation tabs (sticky) -->
|
||||
{% if "navigation.tabs.sticky" in features %}
|
||||
{% if "navigation.tabs" in features %}
|
||||
{% include "partials/tabs.html" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</header>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
comments: true
|
||||
status: new
|
||||
---
|
||||
|
||||
# ByteTrack
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ https://github.com/roboflow/supervision/assets/26109316/f84db7b5-79e2-4142-a1da-
|
|||
- clone repository and navigate to example directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision/examples/count_people_in_zone
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import argparse
|
||||
import json
|
||||
import os
|
||||
from typing import List, Tuple
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -14,7 +13,7 @@ import supervision as sv
|
|||
COLORS = sv.ColorPalette.DEFAULT
|
||||
|
||||
|
||||
def load_zones_config(file_path: str) -> List[np.ndarray]:
|
||||
def load_zones_config(file_path: str) -> list[np.ndarray]:
|
||||
"""
|
||||
Load polygon zone configurations from a JSON file.
|
||||
|
||||
|
|
@ -28,16 +27,14 @@ def load_zones_config(file_path: str) -> List[np.ndarray]:
|
|||
Returns:
|
||||
List[np.ndarray]: A list of polygons, each represented as a NumPy array.
|
||||
"""
|
||||
with open(file_path, "r") as file:
|
||||
with open(file_path) as file:
|
||||
data = json.load(file)
|
||||
return [np.array(polygon, np.int32) for polygon in data["polygons"]]
|
||||
|
||||
|
||||
def initiate_annotators(
|
||||
polygons: List[np.ndarray], resolution_wh: Tuple[int, int]
|
||||
) -> Tuple[
|
||||
List[sv.PolygonZone], List[sv.PolygonZoneAnnotator], List[sv.BoundingBoxAnnotator]
|
||||
]:
|
||||
polygons: list[np.ndarray], resolution_wh: tuple[int, int]
|
||||
) -> tuple[list[sv.PolygonZone], list[sv.PolygonZoneAnnotator], list[sv.BoxAnnotator]]:
|
||||
line_thickness = sv.calculate_optimal_line_thickness(resolution_wh=resolution_wh)
|
||||
text_scale = sv.calculate_optimal_text_scale(resolution_wh=resolution_wh)
|
||||
|
||||
|
|
@ -54,7 +51,7 @@ def initiate_annotators(
|
|||
text_thickness=line_thickness * 2,
|
||||
text_scale=text_scale * 2,
|
||||
)
|
||||
box_annotator = sv.BoundingBoxAnnotator(
|
||||
box_annotator = sv.BoxAnnotator(
|
||||
color=COLORS.by_idx(index), thickness=line_thickness
|
||||
)
|
||||
zones.append(zone)
|
||||
|
|
@ -95,9 +92,9 @@ def detect(
|
|||
|
||||
def annotate(
|
||||
frame: np.ndarray,
|
||||
zones: List[sv.PolygonZone],
|
||||
zone_annotators: List[sv.PolygonZoneAnnotator],
|
||||
box_annotators: List[sv.BoundingBoxAnnotator],
|
||||
zones: list[sv.PolygonZone],
|
||||
zone_annotators: list[sv.PolygonZoneAnnotator],
|
||||
box_annotators: list[sv.BoxAnnotator],
|
||||
detections: sv.Detections,
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
|
|
@ -108,7 +105,7 @@ def annotate(
|
|||
zones (List[sv.PolygonZone]): A list of polygon zones used for detection.
|
||||
zone_annotators (List[sv.PolygonZoneAnnotator]): A list of annotators for
|
||||
drawing zone annotations.
|
||||
box_annotators (List[sv.BoundingBoxAnnotator]): A list of annotators for
|
||||
box_annotators (List[sv.BoxAnnotator]): A list of annotators for
|
||||
drawing box annotations.
|
||||
detections (sv.Detections): Detections to be used for annotation.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
gdown
|
||||
inference==0.9.17
|
||||
supervision>=0.20.0
|
||||
inference
|
||||
supervision
|
||||
tqdm
|
||||
ultralytics
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import argparse
|
||||
import json
|
||||
from typing import List, Tuple
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -12,7 +11,7 @@ import supervision as sv
|
|||
COLORS = sv.ColorPalette.DEFAULT
|
||||
|
||||
|
||||
def load_zones_config(file_path: str) -> List[np.ndarray]:
|
||||
def load_zones_config(file_path: str) -> list[np.ndarray]:
|
||||
"""
|
||||
Load polygon zone configurations from a JSON file.
|
||||
|
||||
|
|
@ -26,16 +25,14 @@ def load_zones_config(file_path: str) -> List[np.ndarray]:
|
|||
Returns:
|
||||
List[np.ndarray]: A list of polygons, each represented as a NumPy array.
|
||||
"""
|
||||
with open(file_path, "r") as file:
|
||||
with open(file_path) as file:
|
||||
data = json.load(file)
|
||||
return [np.array(polygon, np.int32) for polygon in data["polygons"]]
|
||||
|
||||
|
||||
def initiate_annotators(
|
||||
polygons: List[np.ndarray], resolution_wh: Tuple[int, int]
|
||||
) -> Tuple[
|
||||
List[sv.PolygonZone], List[sv.PolygonZoneAnnotator], List[sv.BoundingBoxAnnotator]
|
||||
]:
|
||||
polygons: list[np.ndarray], resolution_wh: tuple[int, int]
|
||||
) -> tuple[list[sv.PolygonZone], list[sv.PolygonZoneAnnotator], list[sv.BoxAnnotator]]:
|
||||
line_thickness = sv.calculate_optimal_line_thickness(resolution_wh=resolution_wh)
|
||||
text_scale = sv.calculate_optimal_text_scale(resolution_wh=resolution_wh)
|
||||
|
||||
|
|
@ -52,7 +49,7 @@ def initiate_annotators(
|
|||
text_thickness=line_thickness * 2,
|
||||
text_scale=text_scale * 2,
|
||||
)
|
||||
box_annotator = sv.BoundingBoxAnnotator(
|
||||
box_annotator = sv.BoxAnnotator(
|
||||
color=COLORS.by_idx(index), thickness=line_thickness
|
||||
)
|
||||
zones.append(zone)
|
||||
|
|
@ -92,9 +89,9 @@ def detect(
|
|||
|
||||
def annotate(
|
||||
frame: np.ndarray,
|
||||
zones: List[sv.PolygonZone],
|
||||
zone_annotators: List[sv.PolygonZoneAnnotator],
|
||||
box_annotators: List[sv.BoundingBoxAnnotator],
|
||||
zones: list[sv.PolygonZone],
|
||||
zone_annotators: list[sv.PolygonZoneAnnotator],
|
||||
box_annotators: list[sv.BoxAnnotator],
|
||||
detections: sv.Detections,
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
|
|
@ -105,7 +102,7 @@ def annotate(
|
|||
zones (List[sv.PolygonZone]): A list of polygon zones used for detection.
|
||||
zone_annotators (List[sv.PolygonZoneAnnotator]): A list of annotators for
|
||||
drawing zone annotations.
|
||||
box_annotators (List[sv.BoundingBoxAnnotator]): A list of annotators for
|
||||
box_annotators (List[sv.BoxAnnotator]): A list of annotators for
|
||||
drawing box annotations.
|
||||
detections (sv.Detections): Detections to be used for annotation.
|
||||
|
||||
|
|
@ -137,7 +134,7 @@ if __name__ == "__main__":
|
|||
)
|
||||
parser.add_argument(
|
||||
"--source_weights_path",
|
||||
default="yolov8x.pt",
|
||||
default="yolo11x.pt",
|
||||
help="Path to the source weights file",
|
||||
type=str,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ supervision package for multiple tasks such as drawing heatmap annotations, trac
|
|||
- clone repository and navigate to example directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision/examples/heatmap_and_track
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
supervision[assets]==0.19.0
|
||||
supervision
|
||||
ultralytics
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ https://github.com/roboflow/supervision/assets/26109316/d50118c1-2ae4-458d-915a-
|
|||
- clone repository and navigate to example directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision/examples/speed_estimation
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
supervision>=0.20.0
|
||||
tqdm==4.66.3
|
||||
supervision
|
||||
tqdm
|
||||
requests
|
||||
ultralytics==8.0.237
|
||||
ultralytics
|
||||
super-gradients==3.5.0
|
||||
inference==0.9.17
|
||||
inference
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ if __name__ == "__main__":
|
|||
args = parse_arguments()
|
||||
|
||||
video_info = sv.VideoInfo.from_video_path(video_path=args.source_video_path)
|
||||
model = YOLO("yolov8x.pt")
|
||||
model = YOLO("yolo11x.pt")
|
||||
|
||||
byte_track = sv.ByteTrack(
|
||||
frame_rate=video_info.fps, track_activation_threshold=args.confidence_threshold
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ https://github.com/roboflow/supervision/assets/26109316/d051cc8a-dd15-41d4-aa36-
|
|||
- clone repository and navigate to example directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision/examples/time_in_zone
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
from typing import List
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -22,7 +21,7 @@ def main(
|
|||
model_id: str,
|
||||
confidence: float,
|
||||
iou: float,
|
||||
classes: List[int],
|
||||
classes: list[int],
|
||||
) -> None:
|
||||
model = get_model(model_id=model_id)
|
||||
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
from typing import List
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -22,7 +21,7 @@ def main(
|
|||
model_id: str,
|
||||
confidence: float,
|
||||
iou: float,
|
||||
classes: List[int],
|
||||
classes: list[int],
|
||||
) -> None:
|
||||
model = get_model(model_id=model_id)
|
||||
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
from typing import List
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -18,7 +17,7 @@ LABEL_ANNOTATOR = sv.LabelAnnotator(
|
|||
|
||||
|
||||
class CustomSink:
|
||||
def __init__(self, zone_configuration_path: str, classes: List[int]):
|
||||
def __init__(self, zone_configuration_path: str, classes: list[int]):
|
||||
self.classes = classes
|
||||
self.tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
|
||||
self.fps_monitor = sv.FPSMonitor()
|
||||
|
|
@ -83,7 +82,7 @@ def main(
|
|||
model_id: str,
|
||||
confidence: float,
|
||||
iou: float,
|
||||
classes: List[int],
|
||||
classes: list[int],
|
||||
) -> None:
|
||||
sink = CustomSink(zone_configuration_path=zone_configuration_path, classes=classes)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
opencv-python
|
||||
supervision>=0.20.0
|
||||
supervision
|
||||
ultralytics
|
||||
inference==0.9.17
|
||||
inference
|
||||
pytube
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
from pytube import YouTube
|
||||
|
||||
|
||||
def main(url: str, output_path: Optional[str], file_name: Optional[str]) -> None:
|
||||
def main(url: str, output_path: str | None, file_name: str | None) -> None:
|
||||
yt = YouTube(url)
|
||||
stream = yt.streams.get_highest_resolution()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Optional, Tuple
|
||||
from typing import Any
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -19,10 +21,10 @@ COLORS = sv.ColorPalette.DEFAULT
|
|||
WINDOW_NAME = "Draw Zones"
|
||||
POLYGONS = [[]]
|
||||
|
||||
current_mouse_position: Optional[Tuple[int, int]] = None
|
||||
current_mouse_position: tuple[int, int] | None = None
|
||||
|
||||
|
||||
def resolve_source(source_path: str) -> Optional[np.ndarray]:
|
||||
def resolve_source(source_path: str) -> np.ndarray | None:
|
||||
if not os.path.exists(source_path):
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
from typing import List
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -23,7 +22,7 @@ def main(
|
|||
device: str,
|
||||
confidence: float,
|
||||
iou: float,
|
||||
classes: List[int],
|
||||
classes: list[int],
|
||||
) -> None:
|
||||
model = YOLO(weights)
|
||||
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
from typing import List
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -23,7 +22,7 @@ def main(
|
|||
device: str,
|
||||
confidence: float,
|
||||
iou: float,
|
||||
classes: List[int],
|
||||
classes: list[int],
|
||||
) -> None:
|
||||
model = YOLO(weights)
|
||||
tracker = sv.ByteTrack(minimum_matching_threshold=0.5)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
from typing import List
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -19,7 +18,7 @@ LABEL_ANNOTATOR = sv.LabelAnnotator(
|
|||
|
||||
|
||||
class CustomSink:
|
||||
def __init__(self, zone_configuration_path: str, classes: List[int]):
|
||||
def __init__(self, zone_configuration_path: str, classes: list[int]):
|
||||
self.classes = classes
|
||||
self.tracker = sv.ByteTrack(minimum_matching_threshold=0.8)
|
||||
self.fps_monitor = sv.FPSMonitor()
|
||||
|
|
@ -84,7 +83,7 @@ def main(
|
|||
device: str,
|
||||
confidence: float,
|
||||
iou: float,
|
||||
classes: List[int],
|
||||
classes: list[int],
|
||||
) -> None:
|
||||
model = YOLO(weights)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import json
|
||||
from typing import Generator, List
|
||||
from collections.abc import Generator
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
def load_zones_config(file_path: str) -> List[np.ndarray]:
|
||||
def load_zones_config(file_path: str) -> list[np.ndarray]:
|
||||
"""
|
||||
Load polygon zone configurations from a JSON file.
|
||||
|
||||
|
|
@ -19,12 +19,12 @@ def load_zones_config(file_path: str) -> List[np.ndarray]:
|
|||
Returns:
|
||||
List[np.ndarray]: A list of polygons, each represented as a NumPy array.
|
||||
"""
|
||||
with open(file_path, "r") as file:
|
||||
with open(file_path) as file:
|
||||
data = json.load(file)
|
||||
return [np.array(polygon, np.int32) for polygon in data]
|
||||
|
||||
|
||||
def find_in_list(array: np.ndarray, search_list: List[int]) -> np.ndarray:
|
||||
def find_in_list(array: np.ndarray, search_list: list[int]) -> np.ndarray:
|
||||
"""Determines if elements of a numpy array are present in a list.
|
||||
|
||||
Args:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from datetime import datetime
|
||||
from typing import Dict
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
|
@ -26,7 +25,7 @@ class FPSBasedTimer:
|
|||
"""
|
||||
self.fps = fps
|
||||
self.frame_id = 0
|
||||
self.tracker_id2frame_id: Dict[int, int] = {}
|
||||
self.tracker_id2frame_id: dict[int, int] = {}
|
||||
|
||||
def tick(self, detections: sv.Detections) -> np.ndarray:
|
||||
"""Processes the current frame, updating time durations for each tracker.
|
||||
|
|
@ -63,7 +62,7 @@ class ClockBasedTimer:
|
|||
|
||||
def __init__(self) -> None:
|
||||
"""Initializes the ClockBasedTimer."""
|
||||
self.tracker_id2start_time: Dict[int, datetime] = {}
|
||||
self.tracker_id2start_time: dict[int, datetime] = {}
|
||||
|
||||
def tick(self, detections: sv.Detections) -> np.ndarray:
|
||||
"""Processes the current frame, updating time durations for each tracker.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ detection and Supervision for tracking and annotation.
|
|||
- clone repository and navigate to example directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision/examples/tracking
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ def process_video(
|
|||
model = get_roboflow_model(model_id=model_id, api_key=roboflow_api_key)
|
||||
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
label_annotator = sv.LabelAnnotator()
|
||||
frame_generator = sv.get_video_frames_generator(source_path=source_video_path)
|
||||
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
inference==0.9.17
|
||||
supervision==0.19.0
|
||||
inference
|
||||
supervision
|
||||
tqdm
|
||||
ultralytics
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ def process_video(
|
|||
model = YOLO(source_weights_path)
|
||||
|
||||
tracker = sv.ByteTrack()
|
||||
box_annotator = sv.BoundingBoxAnnotator()
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
label_annotator = sv.LabelAnnotator()
|
||||
frame_generator = sv.get_video_frames_generator(source_path=source_video_path)
|
||||
video_info = sv.VideoInfo.from_video_path(video_path=source_video_path)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-
|
|||
- clone repository and navigate to example directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/roboflow/supervision.git
|
||||
git clone --depth 1 -b develop https://github.com/roboflow/supervision.git
|
||||
cd supervision/examples/traffic_analysis
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from typing import Dict, Iterable, List, Optional, Set
|
||||
from collections.abc import Iterable
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -29,14 +31,14 @@ ZONE_OUT_POLYGONS = [
|
|||
|
||||
class DetectionsManager:
|
||||
def __init__(self) -> None:
|
||||
self.tracker_id_to_zone_id: Dict[int, int] = {}
|
||||
self.counts: Dict[int, Dict[int, Set[int]]] = {}
|
||||
self.tracker_id_to_zone_id: dict[int, int] = {}
|
||||
self.counts: dict[int, dict[int, set[int]]] = {}
|
||||
|
||||
def update(
|
||||
self,
|
||||
detections_all: sv.Detections,
|
||||
detections_in_zones: List[sv.Detections],
|
||||
detections_out_zones: List[sv.Detections],
|
||||
detections_in_zones: list[sv.Detections],
|
||||
detections_out_zones: list[sv.Detections],
|
||||
) -> sv.Detections:
|
||||
for zone_in_id, detections_in_zone in enumerate(detections_in_zones):
|
||||
for tracker_id in detections_in_zone.tracker_id:
|
||||
|
|
@ -59,9 +61,9 @@ class DetectionsManager:
|
|||
|
||||
|
||||
def initiate_polygon_zones(
|
||||
polygons: List[np.ndarray],
|
||||
polygons: list[np.ndarray],
|
||||
triggering_anchors: Iterable[sv.Position] = [sv.Position.CENTER],
|
||||
) -> List[sv.PolygonZone]:
|
||||
) -> list[sv.PolygonZone]:
|
||||
return [
|
||||
sv.PolygonZone(
|
||||
polygon=polygon,
|
||||
|
|
@ -77,7 +79,7 @@ class VideoProcessor:
|
|||
roboflow_api_key: str,
|
||||
model_id: str,
|
||||
source_video_path: str,
|
||||
target_video_path: Optional[str] = None,
|
||||
target_video_path: str | None = None,
|
||||
confidence_threshold: float = 0.3,
|
||||
iou_threshold: float = 0.7,
|
||||
) -> None:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
gdown
|
||||
inference==0.9.17
|
||||
supervision>=0.20.0
|
||||
inference
|
||||
supervision
|
||||
tqdm
|
||||
ultralytics
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from typing import Dict, Iterable, List, Optional, Set
|
||||
from collections.abc import Iterable
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
|
@ -27,14 +29,14 @@ ZONE_OUT_POLYGONS = [
|
|||
|
||||
class DetectionsManager:
|
||||
def __init__(self) -> None:
|
||||
self.tracker_id_to_zone_id: Dict[int, int] = {}
|
||||
self.counts: Dict[int, Dict[int, Set[int]]] = {}
|
||||
self.tracker_id_to_zone_id: dict[int, int] = {}
|
||||
self.counts: dict[int, dict[int, set[int]]] = {}
|
||||
|
||||
def update(
|
||||
self,
|
||||
detections_all: sv.Detections,
|
||||
detections_in_zones: List[sv.Detections],
|
||||
detections_out_zones: List[sv.Detections],
|
||||
detections_in_zones: list[sv.Detections],
|
||||
detections_out_zones: list[sv.Detections],
|
||||
) -> sv.Detections:
|
||||
for zone_in_id, detections_in_zone in enumerate(detections_in_zones):
|
||||
for tracker_id in detections_in_zone.tracker_id:
|
||||
|
|
@ -57,9 +59,9 @@ class DetectionsManager:
|
|||
|
||||
|
||||
def initiate_polygon_zones(
|
||||
polygons: List[np.ndarray],
|
||||
polygons: list[np.ndarray],
|
||||
triggering_anchors: Iterable[sv.Position] = [sv.Position.CENTER],
|
||||
) -> List[sv.PolygonZone]:
|
||||
) -> list[sv.PolygonZone]:
|
||||
return [
|
||||
sv.PolygonZone(
|
||||
polygon=polygon,
|
||||
|
|
@ -74,7 +76,7 @@ class VideoProcessor:
|
|||
self,
|
||||
source_weights_path: str,
|
||||
source_video_path: str,
|
||||
target_video_path: Optional[str] = None,
|
||||
target_video_path: str | None = None,
|
||||
confidence_threshold: float = 0.3,
|
||||
iou_threshold: float = 0.7,
|
||||
) -> None:
|
||||
|
|
|
|||
48
mkdocs.yml
48
mkdocs.yml
|
|
@ -3,9 +3,8 @@ site_url: https://supervision.roboflow.com/
|
|||
site_author: Roboflow
|
||||
site_description: A set of easy-to-use utilities that will come in handy in any computer vision project.
|
||||
repo_name: roboflow/supervision
|
||||
repo_url: https://github.com/roboflow/supervision
|
||||
edit_uri: https://github.com/roboflow/supervision/tree/main/docs
|
||||
copyright: Roboflow 2024. All rights reserved.
|
||||
copyright: Roboflow 2025. All rights reserved.
|
||||
|
||||
extra:
|
||||
social:
|
||||
|
|
@ -13,12 +12,8 @@ extra:
|
|||
link: https://github.com/roboflow
|
||||
- icon: fontawesome/brands/python
|
||||
link: https://pypi.org/project/supervision
|
||||
- icon: fontawesome/brands/docker
|
||||
link: https://hub.docker.com/u/roboflow
|
||||
- icon: fontawesome/brands/youtube
|
||||
link: https://www.youtube.com/roboflow
|
||||
- icon: fontawesome/brands/linkedin
|
||||
link: https://www.linkedin.com/company/roboflow-ai/
|
||||
- icon: fontawesome/brands/x-twitter
|
||||
link: https://twitter.com/roboflow
|
||||
- icon: fontawesome/brands/discord
|
||||
|
|
@ -34,7 +29,7 @@ extra_css:
|
|||
- stylesheets/cookbooks-card.css
|
||||
|
||||
nav:
|
||||
- Supervision: index.md
|
||||
- Home: index.md
|
||||
- Learn:
|
||||
- Detect and Annotate: how_to/detect_and_annotate.md
|
||||
- Save Detections: how_to/save_detections.md
|
||||
|
|
@ -42,13 +37,16 @@ nav:
|
|||
- Detect Small Objects: how_to/detect_small_objects.md
|
||||
- Track Objects on Video: how_to/track_objects.md
|
||||
- Process Datasets: how_to/process_datasets.md
|
||||
|
||||
- Reference - Code API:
|
||||
- Benchmark a Model: how_to/benchmark_a_model.md
|
||||
- Reference:
|
||||
- Detection and Segmentation:
|
||||
- Core: detection/core.md
|
||||
- Annotators: detection/annotators.md
|
||||
- Double Detection Filter: detection/double_detection_filter.md
|
||||
- Utils: detection/utils.md
|
||||
- Converters: detection/utils/converters.md
|
||||
- IoU and NMS: detection/utils/iou_and_nms.md
|
||||
- Boxes: detection/utils/boxes.md
|
||||
- Masks: detection/utils/masks.md
|
||||
- Polygons: detection/utils/polygons.md
|
||||
- Keypoint Detection:
|
||||
- Core: keypoint/core.md
|
||||
- Annotators: keypoint/annotators.md
|
||||
|
|
@ -82,12 +80,7 @@ nav:
|
|||
- Geometry: utils/geometry.md
|
||||
- Assets: assets.md
|
||||
- Cookbooks: cookbooks.md
|
||||
- Cheatsheet: https://roboflow.github.io/cheatsheet-supervision/
|
||||
- Contribute:
|
||||
- Contributing: contributing.md
|
||||
- Code of Conduct: code_of_conduct.md
|
||||
- License: license.md
|
||||
- Release Notes:
|
||||
- Changelog:
|
||||
- Changelog: changelog.md
|
||||
- Deprecated: deprecated.md
|
||||
|
||||
|
|
@ -105,6 +98,7 @@ theme:
|
|||
- content.tooltips
|
||||
- content.code.annotate
|
||||
- navigation.tabs
|
||||
- navigation.tabs.sticky
|
||||
|
||||
palette:
|
||||
# Palette for light mode
|
||||
|
|
@ -122,11 +116,8 @@ theme:
|
|||
name: Switch to light mode
|
||||
|
||||
font:
|
||||
text: Roboto
|
||||
code: Roboto Mono
|
||||
features:
|
||||
- content.code.copy
|
||||
- content.code.annotate
|
||||
text: Inter
|
||||
code: IBM Plex Mono
|
||||
|
||||
plugins:
|
||||
- search
|
||||
|
|
@ -148,9 +139,12 @@ plugins:
|
|||
group_by_category: true
|
||||
docstring_style: google
|
||||
show_symbol_type_heading: true
|
||||
show_root_heading: True
|
||||
show_symbol_type_toc: true
|
||||
show_category_heading: true
|
||||
domains: [std, py]
|
||||
inventories:
|
||||
- url: https://docs.python-requests.org/en/master/objects.inv
|
||||
domains: [std, py]
|
||||
- git-committers:
|
||||
repository: roboflow/supervision
|
||||
branch: develop
|
||||
|
|
@ -175,12 +169,18 @@ markdown_extensions:
|
|||
check_paths: true
|
||||
- pymdownx.highlight:
|
||||
anchor_linenums: true
|
||||
line_spans: __span
|
||||
pygments_lang_class: true
|
||||
- pymdownx.arithmatex:
|
||||
generic: true
|
||||
|
||||
extra_javascript:
|
||||
- "https://widget.kapa.ai/kapa-widget.bundle.js"
|
||||
- "javascripts/init_kapa_widget.js"
|
||||
- "javascripts/cookbooks-card.js"
|
||||
- "javascripts/segment.js"
|
||||
- "javascripts/mathjax.js"
|
||||
- "https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.8/purify.min.js"
|
||||
- "https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js"
|
||||
|
||||
# Messages shown during document build
|
||||
# Reference: https://www.mkdocs.org/user-guide/configuration/#validation
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
170
pyproject.toml
170
pyproject.toml
|
|
@ -1,18 +1,16 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "supervision"
|
||||
version = "0.25.1"
|
||||
description = "A set of easy-to-use utils that will come in handy in any Computer Vision project"
|
||||
authors = ["Piotr Skalski <piotr.skalski92@gmail.com>"]
|
||||
maintainers = [
|
||||
"Piotr Skalski <piotr.skalski92@gmail.com>",
|
||||
"Linas Kondrackis <linas@roboflow.com>",
|
||||
]
|
||||
license = { text = "MIT" }
|
||||
version = "0.26.0"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
packages = [{ include = "supervision" }, { include = "supervision/py.typed" }]
|
||||
homepage = "https://github.com/roboflow/supervision"
|
||||
repository = "https://github.com/roboflow/supervision"
|
||||
documentation = "https://supervision.roboflow.com/latest/"
|
||||
requires-python = ">=3.9"
|
||||
authors = [
|
||||
{ name = "Piotr Skalski", email = "piotr.skalski92@gmail.com" }
|
||||
]
|
||||
maintainers = [
|
||||
{ name = "Piotr Skalski", email = "piotr.skalski92@gmail.com" },
|
||||
]
|
||||
keywords = [
|
||||
"machine-learning",
|
||||
"deep-learning",
|
||||
|
|
@ -22,7 +20,6 @@ keywords = [
|
|||
"AI",
|
||||
"Roboflow",
|
||||
]
|
||||
|
||||
classifiers = [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
|
|
@ -40,118 +37,63 @@ classifiers = [
|
|||
'Operating System :: POSIX :: Linux',
|
||||
'Operating System :: MacOS',
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
|
||||
# For Python versions 3.13 and above, use numpy versions 2.1.0,
|
||||
# required for poetry to not fail.
|
||||
numpy = [
|
||||
{ version = ">=1.21.2", python = "<3.13" },
|
||||
{ version = ">=2.1.0", python = ">=3.13" },
|
||||
dependencies = [
|
||||
"numpy>=1.21.2",
|
||||
"scipy>=1.10.0",
|
||||
"matplotlib>=3.6.0",
|
||||
"pyyaml>=5.3",
|
||||
"defusedxml>=0.7.1",
|
||||
"pillow>=9.4",
|
||||
"requests>=2.26.0",
|
||||
"tqdm>=4.62.3",
|
||||
"opencv-python>=4.5.5.64"
|
||||
]
|
||||
|
||||
scipy = [
|
||||
{ version = "1.10.0", python = "<3.9" },
|
||||
{ version = "^1.10.0", python = ">=3.9" },
|
||||
{ version = ">=1.14.1", python = ">=3.13" },
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/roboflow/supervision"
|
||||
Repository = "https://github.com/roboflow/supervision"
|
||||
Documentation = "https://supervision.roboflow.com/latest/"
|
||||
|
||||
[project.optional-dependencies]
|
||||
metrics = [
|
||||
"pandas>=2.0.0",
|
||||
]
|
||||
|
||||
# Matplotlib sub-dependency
|
||||
# The 'contourpy' package is required by Matplotlib for contour plotting.
|
||||
# We need to ensure compatibility with both Python 3.8 and Python 3.13.
|
||||
#
|
||||
# For Python 3.8 and above, we use version 1.0.7 or higher, as it is the lowest major version that supports Python 3.8.
|
||||
# For Python 3.13 and above, we use version 1.3.0 or higher, as it is the first version that explicitly supports Python 3.13.
|
||||
contourpy = [
|
||||
{ version = ">=1.0.7", python = ">=3.8,<3.13" },
|
||||
{ version = ">=1.3.0", python = ">=3.13" },
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=7.2.2,<9.0.0",
|
||||
"tox>=4.11.4",
|
||||
"notebook>=6.5.3,<8.0.0",
|
||||
"ipywidgets>=8.1.1",
|
||||
"jupytext>=1.16.1",
|
||||
"nbconvert>=7.14.2",
|
||||
"docutils!=0.21"
|
||||
]
|
||||
|
||||
matplotlib = [
|
||||
{ version = ">=3.6.0,<3.8.0", python = "3.8" },
|
||||
{ version = ">=3.6.0", python = ">=3.9" },
|
||||
{ version = ">=3.7.3", python = ">=3.12" },
|
||||
{ version = ">=3.9.2", python = ">=3.13" },
|
||||
docs = [
|
||||
"mkdocs-material[imaging]>=9.5.5",
|
||||
"mkdocstrings>=0.25.2,<0.30.0",
|
||||
"mkdocstrings-python>=1.10.9",
|
||||
"mike>=2.0.0",
|
||||
"mkdocs-jupyter>=0.24.3",
|
||||
"mkdocs-git-committers-plugin-2>=2.4.1; python_version >= '3.9' and python_version < '4'",
|
||||
"mkdocs-git-revision-date-localized-plugin>=1.2.4"
|
||||
]
|
||||
|
||||
|
||||
pyyaml = ">=5.3"
|
||||
defusedxml = "^0.7.1"
|
||||
pillow = ">=9.4"
|
||||
requests = ">=2.26.0"
|
||||
tqdm = ">=4.62.3"
|
||||
# pandas: picked lowest major version that supports Python 3.8
|
||||
# pandas 2.2.3 has been released with support for Python 3.13
|
||||
pandas = [
|
||||
{ version = ">=2.0.0", python = "<3.13", optional = true },
|
||||
{ version = ">=2.2.3", python = ">=3.13", optional = true },
|
||||
build = [
|
||||
"twine>=5.1.1,<7.0.0",
|
||||
"wheel>=0.40,<0.46",
|
||||
"build>=0.10,<1.3"
|
||||
]
|
||||
|
||||
opencv-python = ">=4.5.5.64"
|
||||
|
||||
[tool.poetry.extras]
|
||||
metrics = ["pandas"]
|
||||
|
||||
[tool.poetry.group.test.dependencies]
|
||||
pytest = ">=7.2.2,<9.0.0"
|
||||
pytest-md = "^0.2.0"
|
||||
pytest-emoji = "^0.2.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
twine = ">=5.1.1,<7.0.0"
|
||||
pytest = ">=7.2.2,<9.0.0"
|
||||
wheel = ">=0.40,<0.46"
|
||||
build = ">=0.10,<1.3"
|
||||
ruff = ">=0.1.0"
|
||||
mypy = "^1.4.1"
|
||||
pre-commit = "^3.3.3"
|
||||
tox = "^4.11.4"
|
||||
notebook = ">=6.5.3,<8.0.0"
|
||||
ipywidgets = "^8.1.1"
|
||||
jupytext = "^1.16.1"
|
||||
nbconvert = "^7.14.2"
|
||||
docutils = [
|
||||
{ version = "^0.20.1", python = "<3.9" },
|
||||
{ version = "^0.21.1", python = ">=3.9" },
|
||||
]
|
||||
|
||||
[tool.poetry.group.docs.dependencies]
|
||||
mkdocs-material = { extras = ["imaging"], version = "^9.5.5" }
|
||||
mkdocstrings = ">=0.25.2,<0.27.0"
|
||||
mkdocstrings-python = "^1.10.9"
|
||||
mike = "^2.0.0"
|
||||
# For Documentation Development use Python 3.10 or above
|
||||
# Use Latest mkdocs-jupyter min 0.24.6 for Jupyter Notebook Theme support
|
||||
mkdocs-jupyter = "^0.24.3"
|
||||
mkdocs-git-committers-plugin-2 = "^2.4.1"
|
||||
mkdocs-git-revision-date-localized-plugin = "^1.2.4"
|
||||
|
||||
[tool.poetry.group.typecheck]
|
||||
optional = true
|
||||
|
||||
[tool.poetry.group.typecheck.dependencies]
|
||||
types-pyyaml = "^6.0.12.20240808"
|
||||
types-cffi = "^1.16.0.20240331"
|
||||
types-requests = "^2.32.0.20240712"
|
||||
types-tqdm = "^4.66.0.20240417"
|
||||
pandas-stubs = ">=2.0.0.230412"
|
||||
|
||||
[tool.poetry.group.build.dependencies]
|
||||
twine = ">=5.1.1,<7.0.0"
|
||||
|
||||
[tool.bandit]
|
||||
target = ["test", "supervision"]
|
||||
tests = ["B201", "B301", "B318", "B314", "B303", "B413", "B412", "B410"]
|
||||
tests = ["B201", "B301", "B318", "B314", "B303", "B413", "B412"]
|
||||
|
||||
[tool.autoflake]
|
||||
check = true
|
||||
imports = ["cv2", "supervision"]
|
||||
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py38"
|
||||
target-version = "py39"
|
||||
|
||||
# Exclude a variety of commonly ignored directories.
|
||||
exclude = [
|
||||
|
|
@ -186,7 +128,7 @@ indent-width = 4
|
|||
|
||||
[tool.ruff.lint]
|
||||
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
|
||||
select = ["E", "F", "I", "A", "Q", "W", "RUF"]
|
||||
select = ["E", "F", "I", "A", "Q", "W", "RUF", "UP"]
|
||||
ignore = []
|
||||
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
||||
fixable = [
|
||||
|
|
@ -273,7 +215,7 @@ skip-magic-trailing-comma = false
|
|||
line-ending = "auto"
|
||||
|
||||
[tool.codespell]
|
||||
skip = "*.ipynb,poetry.lock"
|
||||
skip = "*.ipynb"
|
||||
count = true
|
||||
quiet-level = 3
|
||||
ignore-words-list = "STrack,sTrack,strack"
|
||||
|
|
@ -282,8 +224,12 @@ ignore-words-list = "STrack,sTrack,strack"
|
|||
include-package-data = false
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["supervision*"]
|
||||
exclude = ["docs*", "test*", "examples*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
supervision = ["py.typed"]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["setuptools >= 61.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ except importlib_metadata.PackageNotFoundError:
|
|||
from supervision.annotators.core import (
|
||||
BackgroundOverlayAnnotator,
|
||||
BlurAnnotator,
|
||||
BoundingBoxAnnotator,
|
||||
BoxAnnotator,
|
||||
BoxCornerAnnotator,
|
||||
CircleAnnotator,
|
||||
ColorAnnotator,
|
||||
ComparisonAnnotator,
|
||||
CropAnnotator,
|
||||
DotAnnotator,
|
||||
EllipseAnnotator,
|
||||
|
|
@ -38,6 +38,7 @@ from supervision.dataset.core import (
|
|||
ClassificationDataset,
|
||||
DetectionDataset,
|
||||
)
|
||||
from supervision.dataset.formats.coco import get_coco_class_index_mapping
|
||||
from supervision.dataset.utils import mask_to_rle, rle_to_mask
|
||||
from supervision.detection.core import Detections
|
||||
from supervision.detection.line_zone import (
|
||||
|
|
@ -45,38 +46,53 @@ from supervision.detection.line_zone import (
|
|||
LineZoneAnnotator,
|
||||
LineZoneAnnotatorMulticlass,
|
||||
)
|
||||
from supervision.detection.lmm import LMM
|
||||
from supervision.detection.overlap_filter import (
|
||||
OverlapFilter,
|
||||
box_non_max_merge,
|
||||
box_non_max_suppression,
|
||||
mask_non_max_suppression,
|
||||
)
|
||||
from supervision.detection.tools.csv_sink import CSVSink
|
||||
from supervision.detection.tools.inference_slicer import InferenceSlicer
|
||||
from supervision.detection.tools.json_sink import JSONSink
|
||||
from supervision.detection.tools.polygon_zone import PolygonZone, PolygonZoneAnnotator
|
||||
from supervision.detection.tools.smoother import DetectionsSmoother
|
||||
from supervision.detection.utils import (
|
||||
box_iou_batch,
|
||||
calculate_masks_centroids,
|
||||
from supervision.detection.utils.boxes import (
|
||||
clip_boxes,
|
||||
contains_holes,
|
||||
contains_multiple_segments,
|
||||
filter_polygons_by_area,
|
||||
mask_iou_batch,
|
||||
denormalize_boxes,
|
||||
move_boxes,
|
||||
pad_boxes,
|
||||
scale_boxes,
|
||||
)
|
||||
from supervision.detection.utils.converters import (
|
||||
mask_to_polygons,
|
||||
mask_to_xyxy,
|
||||
move_boxes,
|
||||
move_masks,
|
||||
oriented_box_iou_batch,
|
||||
pad_boxes,
|
||||
polygon_to_mask,
|
||||
polygon_to_xyxy,
|
||||
scale_boxes,
|
||||
xcycwh_to_xyxy,
|
||||
xywh_to_xyxy,
|
||||
xyxy_to_polygons,
|
||||
xyxy_to_xcycarh,
|
||||
xyxy_to_xywh,
|
||||
)
|
||||
from supervision.detection.utils.iou_and_nms import (
|
||||
OverlapFilter,
|
||||
OverlapMetric,
|
||||
box_iou,
|
||||
box_iou_batch,
|
||||
box_iou_batch_with_jaccard,
|
||||
box_non_max_merge,
|
||||
box_non_max_suppression,
|
||||
mask_iou_batch,
|
||||
mask_non_max_merge,
|
||||
mask_non_max_suppression,
|
||||
oriented_box_iou_batch,
|
||||
)
|
||||
from supervision.detection.utils.masks import (
|
||||
calculate_masks_centroids,
|
||||
contains_holes,
|
||||
contains_multiple_segments,
|
||||
move_masks,
|
||||
)
|
||||
from supervision.detection.utils.polygons import (
|
||||
approximate_polygon,
|
||||
filter_polygons_by_area,
|
||||
)
|
||||
from supervision.detection.vlm import LMM, VLM
|
||||
from supervision.draw.color import Color, ColorPalette
|
||||
from supervision.draw.utils import (
|
||||
calculate_optimal_line_thickness,
|
||||
|
|
@ -118,3 +134,117 @@ from supervision.utils.video import (
|
|||
get_video_frames_generator,
|
||||
process_video,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"LMM",
|
||||
"BackgroundOverlayAnnotator",
|
||||
"BaseDataset",
|
||||
"BlurAnnotator",
|
||||
"BoxAnnotator",
|
||||
"BoxCornerAnnotator",
|
||||
"ByteTrack",
|
||||
"CSVSink",
|
||||
"CircleAnnotator",
|
||||
"ClassificationDataset",
|
||||
"Classifications",
|
||||
"Color",
|
||||
"ColorAnnotator",
|
||||
"ColorLookup",
|
||||
"ColorPalette",
|
||||
"ComparisonAnnotator",
|
||||
"ConfusionMatrix",
|
||||
"CropAnnotator",
|
||||
"DetectionDataset",
|
||||
"Detections",
|
||||
"DetectionsSmoother",
|
||||
"DotAnnotator",
|
||||
"EdgeAnnotator",
|
||||
"EllipseAnnotator",
|
||||
"FPSMonitor",
|
||||
"HaloAnnotator",
|
||||
"HeatMapAnnotator",
|
||||
"IconAnnotator",
|
||||
"ImageSink",
|
||||
"InferenceSlicer",
|
||||
"JSONSink",
|
||||
"KeyPoints",
|
||||
"LabelAnnotator",
|
||||
"LineZone",
|
||||
"LineZoneAnnotator",
|
||||
"LineZoneAnnotatorMulticlass",
|
||||
"MaskAnnotator",
|
||||
"MeanAveragePrecision",
|
||||
"OrientedBoxAnnotator",
|
||||
"OverlapFilter",
|
||||
"OverlapMetric",
|
||||
"PercentageBarAnnotator",
|
||||
"PixelateAnnotator",
|
||||
"Point",
|
||||
"PolygonAnnotator",
|
||||
"PolygonZone",
|
||||
"PolygonZoneAnnotator",
|
||||
"Position",
|
||||
"Rect",
|
||||
"RichLabelAnnotator",
|
||||
"RoundBoxAnnotator",
|
||||
"TraceAnnotator",
|
||||
"TriangleAnnotator",
|
||||
"VertexAnnotator",
|
||||
"VertexLabelAnnotator",
|
||||
"VideoInfo",
|
||||
"VideoSink",
|
||||
"approximate_polygon",
|
||||
"box_iou",
|
||||
"box_iou_batch",
|
||||
"box_iou_batch_with_jaccard",
|
||||
"box_non_max_merge",
|
||||
"box_non_max_suppression",
|
||||
"calculate_masks_centroids",
|
||||
"calculate_optimal_line_thickness",
|
||||
"calculate_optimal_text_scale",
|
||||
"clip_boxes",
|
||||
"contains_holes",
|
||||
"contains_multiple_segments",
|
||||
"create_tiles",
|
||||
"crop_image",
|
||||
"cv2_to_pillow",
|
||||
"draw_filled_polygon",
|
||||
"draw_filled_rectangle",
|
||||
"draw_image",
|
||||
"draw_line",
|
||||
"draw_polygon",
|
||||
"draw_rectangle",
|
||||
"draw_text",
|
||||
"filter_polygons_by_area",
|
||||
"get_coco_class_index_mapping",
|
||||
"get_polygon_center",
|
||||
"get_video_frames_generator",
|
||||
"letterbox_image",
|
||||
"list_files_with_extensions",
|
||||
"mask_iou_batch",
|
||||
"mask_non_max_merge",
|
||||
"mask_non_max_suppression",
|
||||
"mask_to_polygons",
|
||||
"mask_to_rle",
|
||||
"mask_to_xyxy",
|
||||
"move_boxes",
|
||||
"move_masks",
|
||||
"oriented_box_iou_batch",
|
||||
"overlay_image",
|
||||
"pad_boxes",
|
||||
"pillow_to_cv2",
|
||||
"plot_image",
|
||||
"plot_images_grid",
|
||||
"polygon_to_mask",
|
||||
"polygon_to_xyxy",
|
||||
"process_video",
|
||||
"resize_image",
|
||||
"rle_to_mask",
|
||||
"scale_boxes",
|
||||
"scale_image",
|
||||
"xcycwh_to_xyxy",
|
||||
"xywh_to_xyxy",
|
||||
"xyxy_to_polygons",
|
||||
"xyxy_to_xcycarh",
|
||||
"xyxy_to_xywh",
|
||||
]
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,12 +1,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
from enum import Enum
|
||||
from typing import Optional, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
|
||||
from supervision.config import CLASS_NAME_DATA_FIELD
|
||||
from supervision.detection.core import Detections
|
||||
from supervision.draw.color import Color, ColorPalette
|
||||
from supervision.geometry.core import Position
|
||||
|
||||
PENDING_TRACK_COLOR = Color.GREY
|
||||
PENDING_TRACK_ID = -1
|
||||
|
||||
|
||||
class ColorLookup(Enum):
|
||||
"""
|
||||
|
|
@ -30,7 +36,7 @@ class ColorLookup(Enum):
|
|||
def resolve_color_idx(
|
||||
detections: Detections,
|
||||
detection_idx: int,
|
||||
color_lookup: Union[ColorLookup, np.ndarray] = ColorLookup.CLASS,
|
||||
color_lookup: ColorLookup | np.ndarray = ColorLookup.CLASS,
|
||||
) -> int:
|
||||
if detection_idx >= len(detections):
|
||||
raise ValueError(
|
||||
|
|
@ -67,10 +73,10 @@ def resolve_color_idx(
|
|||
|
||||
|
||||
def resolve_text_background_xyxy(
|
||||
center_coordinates: Tuple[int, int],
|
||||
text_wh: Tuple[int, int],
|
||||
center_coordinates: tuple[int, int],
|
||||
text_wh: tuple[int, int],
|
||||
position: Position,
|
||||
) -> Tuple[int, int, int, int]:
|
||||
) -> tuple[int, int, int, int]:
|
||||
center_x, center_y = center_coordinates
|
||||
text_w, text_h = text_wh
|
||||
|
||||
|
|
@ -119,30 +125,192 @@ def resolve_text_background_xyxy(
|
|||
)
|
||||
|
||||
|
||||
def get_color_by_index(color: Union[Color, ColorPalette], idx: int) -> Color:
|
||||
def get_color_by_index(color: Color | ColorPalette, idx: int) -> Color:
|
||||
if isinstance(color, ColorPalette):
|
||||
return color.by_idx(idx)
|
||||
return color
|
||||
|
||||
|
||||
def resolve_color(
|
||||
color: Union[Color, ColorPalette],
|
||||
color: Color | ColorPalette,
|
||||
detections: Detections,
|
||||
detection_idx: int,
|
||||
color_lookup: Union[ColorLookup, np.ndarray] = ColorLookup.CLASS,
|
||||
color_lookup: ColorLookup | np.ndarray = ColorLookup.CLASS,
|
||||
) -> Color:
|
||||
idx = resolve_color_idx(
|
||||
detections=detections,
|
||||
detection_idx=detection_idx,
|
||||
color_lookup=color_lookup,
|
||||
)
|
||||
if color_lookup == ColorLookup.TRACK and idx == PENDING_TRACK_ID:
|
||||
return PENDING_TRACK_COLOR
|
||||
return get_color_by_index(color=color, idx=idx)
|
||||
|
||||
|
||||
def wrap_text(text: str, max_line_length=None) -> list[str]:
|
||||
"""
|
||||
Wraps text to the specified maximum line length, respecting existing newlines.
|
||||
Uses the textwrap library for robust text wrapping.
|
||||
|
||||
Args:
|
||||
text (str): The text to wrap.
|
||||
|
||||
Returns:
|
||||
List[str]: A list of text lines after wrapping.
|
||||
"""
|
||||
|
||||
if not text:
|
||||
return [""]
|
||||
|
||||
if max_line_length is None:
|
||||
return text.splitlines() or [""]
|
||||
|
||||
paragraphs = text.split("\n")
|
||||
all_lines = []
|
||||
|
||||
for paragraph in paragraphs:
|
||||
if not paragraph:
|
||||
# Keep empty lines
|
||||
all_lines.append("")
|
||||
continue
|
||||
|
||||
wrapped = textwrap.wrap(
|
||||
paragraph,
|
||||
width=max_line_length,
|
||||
break_long_words=True,
|
||||
replace_whitespace=False,
|
||||
drop_whitespace=True,
|
||||
)
|
||||
|
||||
if wrapped:
|
||||
all_lines.extend(wrapped)
|
||||
else:
|
||||
all_lines.append("")
|
||||
|
||||
return all_lines if all_lines else [""]
|
||||
|
||||
|
||||
def validate_labels(labels: list[str] | None, detections: Detections):
|
||||
"""
|
||||
Validates that the number of provided labels matches the number of detections.
|
||||
|
||||
Args:
|
||||
labels (Optional[List[str]]): A list of labels, one for each detection. Can
|
||||
be None.
|
||||
detections (Detections): The detections to be labeled.
|
||||
|
||||
Raises:
|
||||
ValueError: If `labels` is not None and its length does not match the number
|
||||
of detections.
|
||||
"""
|
||||
if labels is not None and len(labels) != len(detections):
|
||||
raise ValueError(
|
||||
f"The number of labels ({len(labels)}) does not match the "
|
||||
f"number of detections ({len(detections)}). Each detection "
|
||||
f"should have exactly 1 label."
|
||||
)
|
||||
|
||||
|
||||
def get_labels_text(
|
||||
detections: Detections, custom_labels: list[str] | None
|
||||
) -> list[str]:
|
||||
"""
|
||||
Retrieves the text labels for the detections.
|
||||
|
||||
If `custom_labels` are provided, they are used. Otherwise, the labels are
|
||||
extracted from the `detections` object, prioritizing the 'class_name' field,
|
||||
then the `class_id`, and finally using the detection index as a string.
|
||||
|
||||
Args:
|
||||
detections (Detections): The detections to get labels for.
|
||||
custom_labels (Optional[List[str]]): An optional list of custom labels.
|
||||
|
||||
Returns:
|
||||
List[str]: A list of text labels for each detection.
|
||||
"""
|
||||
if custom_labels is not None:
|
||||
return custom_labels
|
||||
|
||||
labels = []
|
||||
for idx in range(len(detections)):
|
||||
if CLASS_NAME_DATA_FIELD in detections.data:
|
||||
labels.append(detections.data[CLASS_NAME_DATA_FIELD][idx])
|
||||
elif detections.class_id is not None:
|
||||
labels.append(str(detections.class_id[idx]))
|
||||
else:
|
||||
labels.append(str(idx))
|
||||
return labels
|
||||
|
||||
|
||||
def snap_boxes(xyxy: np.ndarray, resolution_wh: tuple[int, int]) -> np.ndarray:
|
||||
"""
|
||||
Shifts `label` bounding boxes into the frame so that they are fully contained
|
||||
within the given resolution, prioritizing the top/left edge.
|
||||
Unlike `clip_boxes`, this function does not crop boxes.
|
||||
It moves them entirely if they exceed the frame boundaries.
|
||||
|
||||
Args:
|
||||
xyxy (np.ndarray): A numpy array of shape `(N, 4)` where each
|
||||
row corresponds to a bounding box in the format
|
||||
`(x_min, y_min, x_max, y_max)`.
|
||||
resolution_wh (Tuple[int, int]): A tuple `(width, height)`
|
||||
representing the resolution of the frame.
|
||||
|
||||
Returns:
|
||||
np.ndarray: A numpy array of shape `(N, 4)` with boxes shifted into frame.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
# Example boxes:
|
||||
xyxy = np.array([
|
||||
[-10, 10, 30, 50], # Off left edge
|
||||
[310, 200, 350, 250], # Off right edge
|
||||
[100, -20, 150, 30], # Off top edge
|
||||
[200, 220, 250, 270], # Off bottom edge
|
||||
[-20, 10, 350, 50], # Wider than frame (370 vs 320)
|
||||
[10, -20, 30, 260] # Taller than frame (280 vs 240)
|
||||
])
|
||||
|
||||
resolution_wh = (320, 240)
|
||||
snapped_boxes = snap_boxes(xyxy=xyxy, resolution_wh=resolution_wh)
|
||||
|
||||
# Results:
|
||||
# [[ 0 10 40 50] # Left edge shifted right
|
||||
# [280 200 320 250] # Right edge shifted left
|
||||
# [100 0 150 50] # Top edge shifted down
|
||||
# [200 190 250 240] # Bottom edge shifted up
|
||||
# [ 0 10 370 50] # Wide box aligned to left edge
|
||||
# [ 10 0 30 280]] # Tall box aligned to top edge
|
||||
```
|
||||
"""
|
||||
result = np.copy(xyxy)
|
||||
width, height = resolution_wh
|
||||
|
||||
# X-axis (prioritize left edge)
|
||||
left_overflow = result[:, 0] < 0
|
||||
result[left_overflow, 0:3:2] -= result[left_overflow, 0:1]
|
||||
|
||||
right_overflow = (~left_overflow) & (result[:, 2] > width)
|
||||
right_shift = width - result[right_overflow, 2]
|
||||
result[right_overflow, 0:3:2] += right_shift[:, np.newaxis]
|
||||
|
||||
# Y-axis (prioritize top edge)
|
||||
top_overflow = result[:, 1] < 0
|
||||
result[top_overflow, 1:4:2] -= result[top_overflow, 1:2]
|
||||
|
||||
bottom_overflow = (~top_overflow) & (result[:, 3] > height)
|
||||
bottom_shift = height - result[bottom_overflow, 3]
|
||||
result[bottom_overflow, 1:4:2] += bottom_shift[:, np.newaxis]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class Trace:
|
||||
def __init__(
|
||||
self,
|
||||
max_size: Optional[int] = None,
|
||||
max_size: int | None = None,
|
||||
start_frame_id: int = 0,
|
||||
anchor: Position = Position.CENTER,
|
||||
) -> None:
|
||||
|
|
@ -158,7 +326,10 @@ class Trace:
|
|||
frame_id = np.full(len(detections), self.current_frame_id, dtype=int)
|
||||
self.frame_id = np.concatenate([self.frame_id, frame_id])
|
||||
self.xy = np.concatenate(
|
||||
[self.xy, detections.get_anchors_coordinates(self.anchor)]
|
||||
[
|
||||
self.xy,
|
||||
detections.get_anchors_coordinates(self.anchor),
|
||||
]
|
||||
)
|
||||
self.tracker_id = np.concatenate([self.tracker_id, detections.tracker_id])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,4 @@
|
|||
from supervision.assets.downloader import download_assets
|
||||
from supervision.assets.list import VideoAssets
|
||||
|
||||
__all__ = ["VideoAssets", "download_assets"]
|
||||
|
|
|
|||
|
|
@ -1,23 +1,15 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from hashlib import new as hash_new
|
||||
from pathlib import Path
|
||||
from shutil import copyfileobj
|
||||
from typing import Union
|
||||
|
||||
from requests import get
|
||||
from tqdm.auto import tqdm
|
||||
|
||||
from supervision.assets.list import VIDEO_ASSETS, VideoAssets
|
||||
|
||||
try:
|
||||
from requests import get
|
||||
from tqdm.auto import tqdm
|
||||
except ImportError:
|
||||
raise ValueError(
|
||||
"\n"
|
||||
"Please install requests and tqdm to download assets \n"
|
||||
"or install supervision with assets \n"
|
||||
"pip install supervision[assets] \n"
|
||||
"\n"
|
||||
)
|
||||
|
||||
|
||||
def is_md5_hash_matching(filename: str, original_md5_hash: str) -> bool:
|
||||
"""
|
||||
|
|
@ -41,7 +33,7 @@ def is_md5_hash_matching(filename: str, original_md5_hash: str) -> bool:
|
|||
return computed_md5_hash.hexdigest() == original_md5_hash
|
||||
|
||||
|
||||
def download_assets(asset_name: Union[VideoAssets, str]) -> str:
|
||||
def download_assets(asset_name: VideoAssets | str) -> str:
|
||||
"""
|
||||
Download a specified asset if it doesn't already exist or is corrupted.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from enum import Enum
|
||||
from typing import Dict, Tuple
|
||||
|
||||
BASE_VIDEO_URL = "https://media.roboflow.com/supervision/video-examples/"
|
||||
|
||||
|
|
@ -39,7 +38,7 @@ class VideoAssets(Enum):
|
|||
return list(map(lambda c: c.value, cls))
|
||||
|
||||
|
||||
VIDEO_ASSETS: Dict[str, Tuple[str, str]] = {
|
||||
VIDEO_ASSETS: dict[str, tuple[str, str]] = {
|
||||
VideoAssets.VEHICLES.value: (
|
||||
f"{BASE_VIDEO_URL}{VideoAssets.VEHICLES.value}",
|
||||
"8155ff4e4de08cfa25f39de96483f918",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Optional, Tuple
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ def _validate_confidence(confidence: Any, n: int) -> None:
|
|||
@dataclass
|
||||
class Classifications:
|
||||
class_id: np.ndarray
|
||||
confidence: Optional[np.ndarray] = None
|
||||
confidence: np.ndarray | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""
|
||||
|
|
@ -154,7 +154,7 @@ class Classifications:
|
|||
class_id = np.arange(len(confidence))
|
||||
return cls(class_id=class_id, confidence=confidence)
|
||||
|
||||
def get_top_k(self, k: int) -> Tuple[np.ndarray, np.ndarray]:
|
||||
def get_top_k(self, k: int) -> tuple[np.ndarray, np.ndarray]:
|
||||
"""
|
||||
Retrieve the top k class IDs and confidences,
|
||||
ordered in descending order by confidence.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue