Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-build-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
activate-environment: true

- name: 🏗️ Install dependencies
run: uv sync --frozen --group docs
run: uv sync --frozen --group docs --extra headless

- name: 🧪 Test Docs Build
run: mkdocs build --verbose
2 changes: 1 addition & 1 deletion .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
activate-environment: true

- name: 🚀 Install Packages
run: uv sync --frozen --group dev --group docs --extra metrics
run: uv sync --frozen --group dev --group docs --extra metrics --extra headless

- name: 📦 Run the Import test
run: python -c "import supervision; from supervision import assets; from supervision import metrics; print(supervision.__version__)"
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@
Pip install the supervision package in a
[**Python>=3.9**](https://www.python.org/) environment.

```bash
pip install supervision[headless]
```

Supervision requires OpenCV to be installed. We don't automatically install it to avoid conflicts with other packages that may need specific OpenCV variants. Choose the OpenCV variant that best fits your needs:

- `supervision[headless]` - Install with `opencv-python-headless` (recommended for servers)
- `supervision[desktop]` - Install with `opencv-python` (includes GUI support)
- `supervision[desktop-contrib]` - Install with `opencv-contrib-python` (extra modules + GUI)
- `supervision[headless-contrib]` - Install with `opencv-contrib-python-headless` (extra modules, no GUI)

⚠️ **Important**: Only choose one variant — the different `opencv-python` packages cannot coexist in the same environment.
If you have OpenCV already installed, you can install supervision without any extras:

```bash
pip install supervision
```
Expand Down
19 changes: 19 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

### 0.28.0rc0 <small>Unreleased</small>

!!! breaking "Breaking Change"
**OpenCV is required at runtime but is now an optional install-time dependency.** To ensure compatibility with different OpenCV variants (standard, contrib, headless), `opencv-python` has been removed from the core dependencies. Users must now have OpenCV installed either by:

- Explicitly choosing an OpenCV extra when installing supervision (recommended)
- Having a compatible OpenCV package already installed

Installation options:

- `pip install supervision[headless]` - Installs `opencv-python-headless` (recommended for servers)
- `pip install supervision[desktop]` - Installs `opencv-python` (includes GUI support)
- `pip install supervision[desktop-contrib]` - Installs `opencv-contrib-python` (extra modules + GUI)
- `pip install supervision[headless-contrib]` - Installs `opencv-contrib-python-headless` (extra modules, no GUI)

If you already have OpenCV installed: `pip install supervision`

**Note**: Without OpenCV installed, functions that require OpenCV will raise an `ImportError` with instructions on how to install it. This change resolves conflicts where `opencv-python` would override `opencv-contrib-python`, preventing access to extra modules like CSRT tracker.

### 0.27.0 <small>Nov 16, 2025</small>

- Added [#2008](https://github.com/roboflow/supervision/pull/2008): [`sv.filter_segments_by_distance`](https://supervision.roboflow.com/0.27.0/detection/utils/masks/#supervision.detection.utils.masks.filter_segments_by_distance) to keep the largest connected component and nearby components within an absolute or relative distance threshold. Useful for cleaning segmentation predictions from models such as SAM, SAM2, YOLO segmentation, and RF-DETR segmentation.
Expand Down
86 changes: 83 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ You can install `supervision` in a
[![license](https://img.shields.io/pypi/l/supervision)](../LICENSE.md)
[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)

Supervision requires OpenCV. Choose the variant that best fits your needs:

⚠️ **Important**: Only install one OpenCV variant at a time. The different `opencv-python` packages (standard, contrib, headless, etc.) are mutually exclusive and cannot coexist in the same environment.

```bash
# Recommended for servers (no GUI)
pip install supervision[headless]
```

```bash
# For desktop applications (includes GUI support)
pip install supervision[desktop]
```

```bash
# For desktop with extra modules (e.g., CSRT tracker)
pip install supervision[desktop-contrib]
```

```bash
# For servers with extra modules (no GUI)
pip install supervision[headless-contrib]
```

If you already have OpenCV installed:

```bash
pip install supervision
```
Comment on lines +51 to 79
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a warning in the installation documentation that users should only install ONE OpenCV variant at a time. The different opencv-python packages are mutually exclusive and installing multiple extras that include different OpenCV variants will cause conflicts.

For example, add a note like:
"⚠️ Important: Only install one OpenCV variant at a time. The different opencv-python packages (standard, contrib, headless, etc.) are mutually exclusive and cannot coexist in the same environment."

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit 2b67b3d. Added warning in the pip installation section:

⚠️ Important: Only install one OpenCV variant at a time. The different opencv-python packages (standard, contrib, headless, etc.) are mutually exclusive and cannot coexist in the same environment.

Expand All @@ -60,7 +86,23 @@ You can install `supervision` in a
[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)

```bash
poetry add supervision
# With headless OpenCV (recommended for servers)
poetry add supervision[headless]
```

```bash
# With desktop OpenCV (includes GUI)
poetry add supervision[desktop]
```

```bash
# For desktop with extra modules (e.g., CSRT tracker)
poetry add supervision[desktop-contrib]
```

```bash
# For servers with extra modules (no GUI)
poetry add supervision[headless-contrib]
```

=== "uv"
Expand All @@ -70,14 +112,36 @@ You can install `supervision` in a
[![license](https://img.shields.io/pypi/l/supervision)](../LICENSE.md)
[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)

```bash
# With headless OpenCV (recommended for servers)
uv pip install supervision[headless]
```

```bash
# For desktop applications (includes GUI support)
uv pip install supervision[desktop]
```

```bash
# For desktop with extra modules (e.g., CSRT tracker)
uv pip install supervision[desktop-contrib]
```

```bash
# For servers with extra modules (no GUI)
uv pip install supervision[headless-contrib]
```

If you already have OpenCV installed:

```bash
uv pip install supervision
```

For uv projects:

```bash
uv add supervision
uv add supervision --extra headless
```
Comment on lines 115 to 145
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The uv installation instructions are incomplete compared to the pip section. The pip section shows all four OpenCV variants with descriptive comments, but the uv section only shows the headless variant. For consistency and to help users make informed choices, add the other variants:

# For desktop applications (includes GUI support)
uv pip install supervision[desktop]
# For desktop with extra modules (e.g., CSRT tracker)
uv pip install supervision[desktop-contrib]
# For servers with extra modules (no GUI)
uv pip install supervision[headless-contrib]

Also add: "If you already have OpenCV installed: uv pip install supervision"

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit 2b67b3d. Added all 4 OpenCV variants to the uv installation section with descriptive comments, plus instructions for when OpenCV is already installed.


=== "rye"
Expand All @@ -88,7 +152,23 @@ You can install `supervision` in a
[![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision)

```bash
rye add supervision
# With headless OpenCV (recommended for servers)
rye add supervision --features headless
```
Comment on lines 154 to 157
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rye installation instructions are incomplete compared to other installation methods. Only the headless variant is shown. For consistency and to help users make informed choices, add examples for the other variants:

# For desktop applications (includes GUI support)
rye add supervision --features desktop
# For desktop with extra modules (e.g., CSRT tracker)
rye add supervision --features desktop-contrib
# For servers with extra modules (no GUI)
rye add supervision --features headless-contrib

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit 2b67b3d. Added all 4 OpenCV variants to the rye installation section with descriptive comments matching the other package managers.


```bash
# For desktop applications (includes GUI support)
rye add supervision --features desktop
```

```bash
# For desktop with extra modules (e.g., CSRT tracker)
rye add supervision --features desktop-contrib
```

```bash
# For servers with extra modules (no GUI)
rye add supervision --features headless-contrib
```

!!! example "conda/mamba install"
Expand Down
13 changes: 12 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,24 @@ dependencies = [
"defusedxml>=0.7.1",
"matplotlib>=3.6",
"numpy>=1.21.2",
"opencv-python>=4.5.5.64",
"pillow>=9.4",
"pyyaml>=5.3",
"requests>=2.26",
"scipy>=1.10",
"tqdm>=4.62.3",
]
optional-dependencies.desktop = [
"opencv-python>=4.5.5.64",
]
optional-dependencies.desktop-contrib = [
"opencv-contrib-python>=4.5.5.64",
]
optional-dependencies.headless = [
"opencv-python-headless>=4.5.5.64",
]
optional-dependencies.headless-contrib = [
"opencv-contrib-python-headless>=4.5.5.64",
]
optional-dependencies.metrics = [
"pandas>=2",
]
Expand Down
30 changes: 23 additions & 7 deletions src/supervision/annotators/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
from math import sqrt
from typing import Any

import cv2
import numpy as np
import numpy.typing as npt
from PIL import Image, ImageDraw, ImageFont
from scipy.interpolate import splev, splprep

try:
import cv2
except ImportError:
cv2 = None # type: ignore

from supervision.annotators.base import BaseAnnotator
from supervision.annotators.utils import (
PENDING_TRACK_ID,
Expand Down Expand Up @@ -45,7 +49,19 @@
scale_image,
)

CV2_FONT = cv2.FONT_HERSHEY_SIMPLEX
# Lazy initialization for cv2 constants to avoid import errors
CV2_FONT = None


def _get_cv2_font() -> int:
"""Get cv2.FONT_HERSHEY_SIMPLEX constant, ensuring cv2 is installed."""
global CV2_FONT
if CV2_FONT is None:
from supervision.utils.internal import ensure_cv2_installed

ensure_cv2_installed()
CV2_FONT = cv2.FONT_HERSHEY_SIMPLEX
return CV2_FONT


class _BaseLabelAnnotator(BaseAnnotator):
Expand Down Expand Up @@ -1273,7 +1289,7 @@ def _get_label_properties(
for line in wrapped_lines:
(text_w, text_h) = cv2.getTextSize(
text=line,
fontFace=CV2_FONT,
fontFace=_get_cv2_font(),
fontScale=self.text_scale,
thickness=self.text_thickness,
)[0]
Expand Down Expand Up @@ -1356,7 +1372,7 @@ def _draw_labels(
# Use a character with ascenders and descenders as height reference
(_, text_h) = cv2.getTextSize(
text="Tg",
fontFace=CV2_FONT,
fontFace=_get_cv2_font(),
fontScale=self.text_scale,
thickness=self.text_thickness,
)[0]
Expand All @@ -1365,7 +1381,7 @@ def _draw_labels(

(_, text_h) = cv2.getTextSize(
text=line,
fontFace=CV2_FONT,
fontFace=_get_cv2_font(),
fontScale=self.text_scale,
thickness=self.text_thickness,
)[0]
Expand All @@ -1377,7 +1393,7 @@ def _draw_labels(
img=scene,
text=line,
org=(text_x, text_y),
fontFace=CV2_FONT,
fontFace=_get_cv2_font(),
fontScale=self.text_scale,
color=text_color.as_bgr(),
thickness=self.text_thickness,
Expand Down Expand Up @@ -3102,7 +3118,7 @@ def _draw_labels(self, scene: npt.NDArray[np.uint8]) -> None:

(text_w, _) = cv2.getTextSize(
text=text,
fontFace=CV2_FONT,
fontFace=_get_cv2_font(),
fontScale=self.label_scale,
thickness=self.text_thickness,
)[0]
Expand Down
10 changes: 8 additions & 2 deletions src/supervision/dataset/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
from itertools import chain
from pathlib import Path

import cv2
import numpy as np
import numpy.typing as npt

try:
import cv2
except ImportError:
cv2 = None # type: ignore

from supervision.classification.core import Classifications
from supervision.dataset.formats.coco import (
load_coco_annotations,
Expand All @@ -33,7 +37,7 @@
train_test_split,
)
from supervision.detection.core import Detections
from supervision.utils.internal import warn_deprecated
from supervision.utils.internal import ensure_cv2_installed, warn_deprecated
from supervision.utils.iterables import find_duplicates


Expand Down Expand Up @@ -91,6 +95,7 @@ def __init__(

def _get_image(self, image_path: str) -> npt.NDArray[np.uint8]:
"""Assumes that image is in dataset."""
ensure_cv2_installed()
if self._images_in_memory:
return self._images_in_memory[image_path]
image = cv2.imread(image_path)
Expand Down Expand Up @@ -693,6 +698,7 @@ def __init__(

def _get_image(self, image_path: str) -> npt.NDArray[np.uint8]:
"""Assumes that image is in dataset."""
ensure_cv2_installed()
if self._images_in_memory:
return self._images_in_memory[image_path]
image = cv2.imread(image_path)
Expand Down
8 changes: 7 additions & 1 deletion src/supervision/dataset/formats/pascal_voc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
from pathlib import Path
from xml.etree.ElementTree import Element, SubElement

import cv2
import numpy as np
import numpy.typing as npt
from defusedxml.ElementTree import parse, tostring
from defusedxml.minidom import parseString

try:
import cv2
except ImportError:
cv2 = None # type: ignore

from supervision.dataset.utils import approximate_mask_with_polygons
from supervision.detection.core import Detections
from supervision.detection.utils.converters import polygon_to_mask, polygon_to_xyxy
from supervision.utils.file import list_files_with_extensions
from supervision.utils.internal import ensure_cv2_installed


def object_to_pascal_voc(
Expand Down Expand Up @@ -161,6 +166,7 @@ def load_pascal_voc_annotations(
of class names, a list of paths to images, and a dictionary with image
paths as keys and corresponding Detections instances as values.
"""
ensure_cv2_installed()

image_paths = [
str(path)
Expand Down
8 changes: 7 additions & 1 deletion src/supervision/dataset/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@
from pathlib import Path
from typing import TYPE_CHECKING, TypeVar

import cv2
import numpy as np
import numpy.typing as npt

try:
import cv2
except ImportError:
cv2 = None # type: ignore

from supervision.detection.core import Detections
from supervision.detection.utils.converters import mask_to_polygons
from supervision.detection.utils.polygons import (
approximate_polygon,
filter_polygons_by_area,
)
from supervision.utils.internal import ensure_cv2_installed

if TYPE_CHECKING:
from supervision.dataset.core import DetectionDataset
Expand Down Expand Up @@ -101,6 +106,7 @@ def map_detections_class_id(


def save_dataset_images(dataset: DetectionDataset, images_directory_path: str) -> None:
ensure_cv2_installed()
Path(images_directory_path).mkdir(parents=True, exist_ok=True)
for image_path in dataset.image_paths:
final_path = os.path.join(images_directory_path, Path(image_path).name)
Expand Down
Loading