diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..6e7fcd59e8 --- /dev/null +++ b/.github/CODEOWNERS @@ -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 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6de587d18f..42aa0e9c6c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -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" diff --git a/.github/workflows/clear-cache.yml b/.github/workflows/clear-cache.yml index 5b96de4279..a9cf4544fe 100644 --- a/.github/workflows/clear-cache.yml +++ b/.github/workflows/clear-cache.yml @@ -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.`) diff --git a/.github/workflows/combine-dependabot-prs.yml b/.github/workflows/combine-dependabot-prs.yml new file mode 100644 index 0000000000..803f2e1c1d --- /dev/null +++ b/.github/workflows/combine-dependabot-prs.yml @@ -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 diff --git a/.github/workflows/notebook-bot.yml b/.github/workflows/notebook-bot.yml deleted file mode 100644 index 17175f3d4d..0000000000 --- a/.github/workflows/notebook-bot.yml +++ /dev/null @@ -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="

Preview

\n" - msg+="Preview and run these notebook edits with Google Colab:\n\n" - - reviewnb_url="https://app.reviewnb.com/${GITHUB_REPOSITORY}/pull/${PR_NUM}/files/" - msg+="Rendered notebook diffs available on ReviewNB.com.\n" - - msg+="If commits are added to the pull request, synchronize your local branch: git pull origin $HEAD_REF\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}" diff --git a/.github/workflows/poetry-test.yml b/.github/workflows/poetry-test.yml deleted file mode 100644 index 95e2eb7fed..0000000000 --- a/.github/workflows/poetry-test.yml +++ /dev/null @@ -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 diff --git a/.github/workflows/publish-dev-docs.yml b/.github/workflows/publish-dev-docs.yml deleted file mode 100644 index 0661929e34..0000000000 --- a/.github/workflows/publish-dev-docs.yml +++ /dev/null @@ -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 diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml new file mode 100644 index 0000000000..3b05352ef8 --- /dev/null +++ b/.github/workflows/publish-docs.yml @@ -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 diff --git a/.github/workflows/publish-pre-release.yml b/.github/workflows/publish-pre-release.yml new file mode 100644 index 0000000000..f6e410eeb0 --- /dev/null +++ b/.github/workflows/publish-pre-release.yml @@ -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 diff --git a/.github/workflows/publish-release-docs.yml b/.github/workflows/publish-release-docs.yml deleted file mode 100644 index 227100332e..0000000000 --- a/.github/workflows/publish-release-docs.yml +++ /dev/null @@ -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 diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000000..2ba7536f9f --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -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 diff --git a/.github/workflows/publish-test.yml b/.github/workflows/publish-test.yml deleted file mode 100644 index 2cd05bf13d..0000000000 --- a/.github/workflows/publish-test.yml +++ /dev/null @@ -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/ diff --git a/.github/workflows/publish-testpypi.yml b/.github/workflows/publish-testpypi.yml new file mode 100644 index 0000000000..69dd746d13 --- /dev/null +++ b/.github/workflows/publish-testpypi.yml @@ -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 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 17c2629a89..0000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -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/ diff --git a/.github/workflows/test-doc.yml b/.github/workflows/test-doc.yml index b15072902d..01930690be 100644 --- a/.github/workflows/test-doc.yml +++ b/.github/workflows/test-doc.yml @@ -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: + fetch-depth: 0 + + - name: 🐍 Install uv and set Python ${{ matrix.python-version }} + uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1 with: - python-version: '3.10' - - name: πŸ—οΈ Install dependencies and Test Docs Build + 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 diff --git a/.github/workflows/test-min.yml b/.github/workflows/test-min.yml deleted file mode 100644 index 1537a63fe5..0000000000 --- a/.github/workflows/test-min.yml +++ /dev/null @@ -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" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index b33f8e537b..0000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -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" diff --git a/.github/workflows/uv-test.yml b/.github/workflows/uv-test.yml new file mode 100644 index 0000000000..1aa2882ec8 --- /dev/null +++ b/.github/workflows/uv-test.yml @@ -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 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6767146f46..24e432cd54 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a06e34219..d86e08627e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -128,47 +128,47 @@ 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 https://github.com/YOUR_USERNAME/supervision.git + git clone --depth 1 -b develop https://github.com/YOUR_USERNAME/supervision.git cd supervision ``` Replace `YOUR_USERNAME` with your GitHub username. -2. Create and activate a virtual environment: + > 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 - python3 -m venv .venv - source .venv/bin/activate + git clone https://github.com/YOUR_USERNAME/supervision.git + cd supervision ``` -3. Install Poetry: - - Using pip: +2. Create and activate a virtual environment: ```bash - pip install -U pip setuptools - pip install poetry + python3 -m venv .venv + source .venv/bin/activate ``` - Or using pipx (recommended for global installation): +3. Install `uv`: - ```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/). diff --git a/README.md b/README.md index 2aa3cef0fe..43d7cf6fd8 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/demo.ipynb b/demo.ipynb index 3b8cf2dc16..453c8014a9 100644 --- a/demo.ipynb +++ b/demo.ipynb @@ -353,7 +353,7 @@ }, "outputs": [], "source": [ - "!pip install -q ultralytics" + "!pip install -q \"ultralytics<=8.3.40\"" ] }, { diff --git a/docs/assets.md b/docs/assets.md index 2e38ad4722..7135f33f0b 100644 --- a/docs/assets.md +++ b/docs/assets.md @@ -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]" - ``` -

download_assets

diff --git a/docs/changelog.md b/docs/changelog.md index d845e6e9c3..73efcf0b1f 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,179 @@ -# CHANGELOG +# Changelog + +### 0.26.0 Jul 16, 2025 + +!!! 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='Nov 12, 2024 diff --git a/docs/deprecated.md b/docs/deprecated.md index e71407eb01..47ebcc16a7 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -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. diff --git a/docs/detection/annotators.md b/docs/detection/annotators.md index e1071121cd..938c49ff48 100644 --- a/docs/detection/annotators.md +++ b/docs/detection/annotators.md @@ -234,7 +234,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/mask-annotator-example-purple.png){ align=center width="800" } + ![mask-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + mask-annotator-example-purple.png){ align=center width="800" }
@@ -255,7 +256,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![polygon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/polygon-annotator-example-purple.png){ align=center width="800" } + ![polygon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + polygon-annotator-example-purple.png){ align=center width="800" }
@@ -283,7 +285,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" } + ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + label-annotator-example-purple.png){ align=center width="800" }
@@ -314,7 +317,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/label-annotator-example-purple.png){ align=center width="800" } + ![label-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + label-annotator-example-purple.png){ align=center width="800" }
@@ -341,24 +345,32 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![icon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/icon-annotator-example.png){ align=center width="800" } + ![icon-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + icon-annotator-example.png){ align=center width="800" }
-=== "Crop" + === "Blur" @@ -377,7 +389,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/blur-annotator-example-purple.png){ align=center width="800" } + ![blur-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + blur-annotator-example-purple.png){ align=center width="800" }
@@ -398,7 +411,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![pixelate-annotator-example](https://media.roboflow.com/supervision-annotator-examples/pixelate-annotator-example-10.png){ align=center width="800" } + ![pixelate-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + pixelate-annotator-example-10.png){ align=center width="800" }
@@ -429,7 +443,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/trace-annotator-example-purple.png){ align=center width="800" } + ![trace-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + trace-annotator-example-purple.png){ align=center width="800" }
@@ -458,7 +473,8 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![heat-map-annotator-example](https://media.roboflow.com/supervision-annotator-examples/heat-map-annotator-example-purple.png){ align=center width="800" } + ![heat-map-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + heat-map-annotator-example-purple.png){ align=center width="800" }
@@ -479,7 +495,31 @@ Annotators accept detections and apply box or mask visualizations to the detecti
- ![background-overlay-annotator-example](https://media.roboflow.com/supervision-annotator-examples/background-color-annotator-example-purple.png) + ![background-overlay-annotator-example](https://media.roboflow.com/supervision-annotator-examples/background-color-annotator-example-purple.png){ align=center width="800" } + +
+ +=== "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 + ) + ``` + +
+ + ![comparison-annotator-example](https://media.roboflow.com/supervision-annotator-examples/ + comparison-annotator-example.png){ align=center width="800" }
@@ -622,6 +662,12 @@ Annotators accept detections and apply box or mask visualizations to the detecti :::supervision.annotators.core.BackgroundOverlayAnnotator +
+

ComparisonAnnotator

+
+ +:::supervision.annotators.core.ComparisonAnnotator +

ColorLookup

diff --git a/docs/detection/double_detection_filter.md b/docs/detection/double_detection_filter.md deleted file mode 100644 index b026637152..0000000000 --- a/docs/detection/double_detection_filter.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -comments: true ---- - -# Double Detection Filter - -
-

OverlapFilter

-
- -:::supervision.detection.overlap_filter.OverlapFilter - -
-

box_non_max_suppression

-
- -:::supervision.detection.overlap_filter.box_non_max_suppression - -
-

mask_non_max_suppression

-
- -:::supervision.detection.overlap_filter.mask_non_max_suppression - -
-

box_non_max_merge

-
- -:::supervision.detection.overlap_filter.box_non_max_merge diff --git a/docs/detection/tools/line_zone.md b/docs/detection/tools/line_zone.md index 014687f9cc..8bca3cfd40 100644 --- a/docs/detection/tools/line_zone.md +++ b/docs/detection/tools/line_zone.md @@ -1,6 +1,5 @@ --- comments: true -status: new ---
diff --git a/docs/detection/utils.md b/docs/detection/utils.md deleted file mode 100644 index 5f1902b79c..0000000000 --- a/docs/detection/utils.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -comments: true -status: new ---- - -# Detection Utils - - - -:::supervision.detection.utils.box_iou_batch - - - -:::supervision.detection.utils.mask_iou_batch - - - -:::supervision.detection.utils.oriented_box_iou_batch - - - -:::supervision.detection.utils.polygon_to_mask - - - -:::supervision.detection.utils.mask_to_xyxy - - - -:::supervision.detection.utils.mask_to_polygons - - - -:::supervision.detection.utils.polygon_to_xyxy - - - -:::supervision.detection.utils.filter_polygons_by_area - - - -:::supervision.detection.utils.move_boxes - - - -:::supervision.detection.utils.move_masks - - - -:::supervision.detection.utils.scale_boxes - - - -:::supervision.detection.utils.clip_boxes - - - -:::supervision.detection.utils.pad_boxes - - - -:::supervision.detection.utils.xywh_to_xyxy - - - -:::supervision.detection.utils.xcycwh_to_xyxy - - - -:::supervision.detection.utils.contains_holes - - - -:::supervision.detection.utils.contains_multiple_segments diff --git a/docs/detection/utils/boxes.md b/docs/detection/utils/boxes.md new file mode 100644 index 0000000000..63a3231755 --- /dev/null +++ b/docs/detection/utils/boxes.md @@ -0,0 +1,36 @@ +--- +comments: true +status: new +--- + +# Boxes Utils + + + +:::supervision.detection.utils.boxes.move_boxes + + + +:::supervision.detection.utils.boxes.scale_boxes + + + +:::supervision.detection.utils.boxes.clip_boxes + + + +:::supervision.detection.utils.boxes.pad_boxes + + + +:::supervision.detection.utils.boxes.denormalize_boxes diff --git a/docs/detection/utils/converters.md b/docs/detection/utils/converters.md new file mode 100644 index 0000000000..48bec65fe4 --- /dev/null +++ b/docs/detection/utils/converters.md @@ -0,0 +1,60 @@ +--- +comments: true +status: new +--- + +# Converters Utils + + + +:::supervision.detection.utils.converters.xyxy_to_xywh + + + +:::supervision.detection.utils.converters.xywh_to_xyxy + + + +:::supervision.detection.utils.converters.xyxy_to_xcycarh + + + +:::supervision.detection.utils.converters.xcycwh_to_xyxy + + + +:::supervision.detection.utils.converters.xyxy_to_polygons + + + +:::supervision.detection.utils.converters.mask_to_xyxy + + + +:::supervision.detection.utils.converters.mask_to_polygons + + + +:::supervision.detection.utils.converters.polygon_to_mask + + + +:::supervision.detection.utils.converters.polygon_to_xyxy diff --git a/docs/detection/utils/iou_and_nms.md b/docs/detection/utils/iou_and_nms.md new file mode 100644 index 0000000000..2b4e4fc334 --- /dev/null +++ b/docs/detection/utils/iou_and_nms.md @@ -0,0 +1,72 @@ +--- +comments: true +status: new +--- + +# IoU and NMS Utils + + + +:::supervision.detection.utils.iou_and_nms.OverlapFilter + + + +:::supervision.detection.utils.iou_and_nms.OverlapMetric + +
+

box_iou

+
+ +:::supervision.detection.utils.iou_and_nms.box_iou + + + +:::supervision.detection.utils.iou_and_nms.box_iou_batch + + + +:::supervision.detection.utils.iou_and_nms.box_iou_batch_with_jaccard + + + +:::supervision.detection.utils.iou_and_nms.mask_iou_batch + + + +:::supervision.detection.utils.iou_and_nms.oriented_box_iou_batch + + + +:::supervision.detection.utils.iou_and_nms.box_non_max_suppression + + + +:::supervision.detection.utils.iou_and_nms.mask_non_max_suppression + + + +:::supervision.detection.utils.iou_and_nms.box_non_max_merge + + + +:::supervision.detection.utils.iou_and_nms.mask_non_max_merge diff --git a/docs/detection/utils/masks.md b/docs/detection/utils/masks.md new file mode 100644 index 0000000000..9e53a6baa1 --- /dev/null +++ b/docs/detection/utils/masks.md @@ -0,0 +1,24 @@ +--- +comments: true +status: new +--- + +# Masks Utils + + + +:::supervision.detection.utils.masks.move_masks + + + +:::supervision.detection.utils.masks.contains_holes + + + +:::supervision.detection.utils.masks.contains_multiple_segments diff --git a/docs/detection/utils/polygons.md b/docs/detection/utils/polygons.md new file mode 100644 index 0000000000..cd9525345a --- /dev/null +++ b/docs/detection/utils/polygons.md @@ -0,0 +1,18 @@ +--- +comments: true +status: new +--- + +# Polygons Utils + + + +:::supervision.detection.utils.polygons.filter_polygons_by_area + + + +:::supervision.detection.utils.polygons.approximate_polygon diff --git a/docs/how_to/benchmark_a_model.md b/docs/how_to/benchmark_a_model.md new file mode 100644 index 0000000000..bf23ee0890 --- /dev/null +++ b/docs/how_to/benchmark_a_model.md @@ -0,0 +1,441 @@ +--- +comments: true +status: new +--- + +![Corgi Example](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/corgi-sorted-2.png) + +# 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="") +project = rf.workspace("").project("") +dataset = project.version().download("") +``` + +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="") +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 = "/" + 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. + +![Basic Model Comparison](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/basic-model-comparison-corgi.png) + +!!! 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() +``` + +![mAP Plot](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/mAP-plot-corgi.png) + +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() +``` + +![F1 Plot](https://media.roboflow.com/supervision/image-examples/how-to/benchmark-models/f1-score-corgi.png) + +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)! + +![Model Leaderboard Example](https://media.roboflow.com/model-leaderboard/model-leaderboard-example.png) + +## 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! diff --git a/docs/how_to/track_objects.md b/docs/how_to/track_objects.md index 1b321e7fe3..c2be3cef6a 100644 --- a/docs/how_to/track_objects.md +++ b/docs/how_to/track_objects.md @@ -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=) - 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=) 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=) 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=) 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( diff --git a/docs/index.md b/docs/index.md index 08fdb2400f..1a1be7727d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,13 +10,19 @@ hide:

-