Skip to content

Commit

Permalink
Merge branch 'develop' into feat/supervision-cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
LinasKo committed Jun 25, 2024
2 parents 27de665 + c973647 commit a377b54
Show file tree
Hide file tree
Showing 16 changed files with 2,298 additions and 115 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ repos:


- repo: https://github.com/PyCQA/bandit
rev: '1.7.8'
rev: '1.7.9'
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
Expand All @@ -45,7 +45,7 @@ repos:


- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.8
rev: v0.4.9
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

**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! 🤝

[![supervision-hackfest](https://github.com/roboflow/supervision/assets/26109316/c05cc954-b9a6-4ed5-9a52-d0b4b619ff65)](https://github.com/orgs/roboflow/projects/10)
[![supervision-hackfest](https://github.com/roboflow/supervision/assets/26109316/c05cc954-b9a6-4ed5-9a52-d0b4b619ff65)](https://github.com/orgs/roboflow/projects)

## 💻 install

Expand Down Expand Up @@ -86,7 +86,7 @@ len(detections)

### annotators

Supervision offers a wide range of highly customizable [annotators](https://supervision.roboflow.com/latest/annotators/), allowing you to compose the perfect visualization for your use case.
Supervision offers a wide range of highly customizable [annotators](https://supervision.roboflow.com/latest/detection/annotators/), allowing you to compose the perfect visualization for your use case.

```python
import cv2
Expand All @@ -106,7 +106,7 @@ https://github.com/roboflow/supervision/assets/26109316/691e219c-0565-4403-9218-

### datasets

Supervision provides a set of [utils](https://supervision.roboflow.com/latest/datasets/) that allow you to load, split, merge, and save datasets in one of the supported formats.
Supervision provides a set of [utils](https://supervision.roboflow.com/latest/datasets/core/) that allow you to load, split, merge, and save datasets in one of the supported formats.

```python
import supervision as sv
Expand Down
745 changes: 745 additions & 0 deletions docs/notebooks/serialise-detections-to-csv.ipynb

Large diffs are not rendered by default.

779 changes: 779 additions & 0 deletions docs/notebooks/serialise-detections-to-json.ipynb

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions docs/theme/cookbooks.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ <h1>Supervision Cookbooks</h1>
<p class="card repo-card" data-url="/develop/notebooks/object-tracking" data-name="Object Tracking" data-labels="TRACKING, ANNOTATOR" data-version="v0.18.0" data-author="nickherrig"></p>
<p class="card repo-card" data-url="/develop/notebooks/occupancy_analytics" data-name="Analyzing Zone Occupancy" data-labels="ANNOTATOR,DETECTION,ZONES" data-version="v0.19.0" data-author="stellasphere"></p>
<p class="card repo-card" data-url="/develop/notebooks/evaluating-alignment-of-text-to-image-diffusion-models" data-name="Evaluating Alignment of Text-to-image Diffusion Models" data-labels="ANNOTATORS,YOLO WORLD" data-version="v0.19.0rc5" data-author="iamhatesz"></p>
<p class="card repo-card" data-url="/develop/notebooks/serialise-detections-to-csv" data-name="Serialise Detections to a CSV File" data-labels="DETECTIONS,CSV SINK,INFERENCE" data-version="v0.21.0" data-author="onuralpszr"></p>
<p class="card repo-card" data-url="/develop/notebooks/serialise-detections-to-json" data-name="Serialise Detections to a JSON File" data-labels="DETECTIONS,JSON SINK,INFERENCE" data-version="v0.21.0" data-author="onuralpszr"></p>

</div>
</div>
</section>
Expand Down
50 changes: 25 additions & 25 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ classifiers=[

[tool.poetry.dependencies]
python = "^3.8"
numpy = ">=1.21.2"
numpy = ">=1.21.2,<2.0.0"
scipy = [
{ version = "1.10.0", python = "<3.9" },
{ version = "^1.10.0", python = ">=3.9" }
Expand Down
18 changes: 16 additions & 2 deletions supervision/annotators/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def annotate(
return scene

for detection_idx in range(len(detections)):
bbox = np.int0(detections.data.get(ORIENTED_BOX_COORDINATES)[detection_idx])
bbox = np.intp(detections.data.get(ORIENTED_BOX_COORDINATES)[detection_idx])
color = resolve_color(
color=self.color,
detections=detections,
Expand Down Expand Up @@ -833,6 +833,7 @@ def __init__(
radius: int = 4,
position: Position = Position.CENTER,
color_lookup: ColorLookup = ColorLookup.CLASS,
outline_thickness: int = 0,
):
"""
Args:
Expand All @@ -842,11 +843,13 @@ def __init__(
position (Position): The anchor position for placing the dot.
color_lookup (ColorLookup): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACK`.
outline_thickness (int): Thickness of the outline of the dot.
"""
self.color: Union[Color, ColorPalette] = color
self.radius: int = radius
self.position: Position = position
self.color_lookup: ColorLookup = color_lookup
self.outline_thickness = outline_thickness

@convert_for_annotation_method
def annotate(
Expand Down Expand Up @@ -898,7 +901,12 @@ def annotate(
else custom_color_lookup,
)
center = (int(xy[detection_idx, 0]), int(xy[detection_idx, 1]))

cv2.circle(scene, center, self.radius, color.as_bgr(), -1)
if self.outline_thickness:
cv2.circle(
scene, center, self.radius, (0, 0, 0), self.outline_thickness
)
return scene


Expand Down Expand Up @@ -1613,6 +1621,7 @@ def __init__(
height: int = 10,
position: Position = Position.TOP_CENTER,
color_lookup: ColorLookup = ColorLookup.CLASS,
outline_thickness: int = 0,
):
"""
Args:
Expand All @@ -1623,12 +1632,14 @@ def __init__(
position (Position): The anchor position for placing the triangle.
color_lookup (ColorLookup): Strategy for mapping colors to annotations.
Options are `INDEX`, `CLASS`, `TRACK`.
outline_thickness (int): Thickness of the outline of the triangle.
"""
self.color: Union[Color, ColorPalette] = color
self.base: int = base
self.height: int = height
self.position: Position = position
self.color_lookup: ColorLookup = color_lookup
self.outline_thickness: int = outline_thickness

@convert_for_annotation_method
def annotate(
Expand Down Expand Up @@ -1690,7 +1701,10 @@ def annotate(
)

cv2.fillPoly(scene, [vertices], color.as_bgr())

if self.outline_thickness:
cv2.polylines(
scene, [vertices], True, (0, 0, 0), thickness=self.outline_thickness
)
return scene


Expand Down
5 changes: 5 additions & 0 deletions supervision/dataset/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def from_yolo(
annotations_directory_path: str,
data_yaml_path: str,
force_masks: bool = False,
is_obb: bool = False,
) -> DetectionDataset:
"""
Creates a Dataset instance from YOLO formatted data.
Expand All @@ -280,6 +281,9 @@ def from_yolo(
force_masks (bool, optional): If True, forces
masks to be loaded for all annotations,
regardless of whether they are present.
is_obb (bool, optional): If True, loads the annotations in OBB format.
OBB annotations are defined as `[class_id, x, y, x, y, x, y, x, y]`,
where pairs of [x, y] are box corners.
Returns:
DetectionDataset: A DetectionDataset instance
Expand Down Expand Up @@ -312,6 +316,7 @@ def from_yolo(
annotations_directory_path=annotations_directory_path,
data_yaml_path=data_yaml_path,
force_masks=force_masks,
is_obb=is_obb,
)
return DetectionDataset(classes=classes, images=images, annotations=annotations)

Expand Down
31 changes: 25 additions & 6 deletions supervision/dataset/formats/yolo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import cv2
import numpy as np

from supervision.config import ORIENTED_BOX_COORDINATES
from supervision.dataset.utils import approximate_mask_with_polygons
from supervision.detection.core import Detections
from supervision.detection.utils import polygon_to_mask, polygon_to_xyxy
Expand Down Expand Up @@ -70,12 +71,15 @@ def _image_name_to_annotation_name(image_name: str) -> str:


def yolo_annotations_to_detections(
lines: List[str], resolution_wh: Tuple[int, int], with_masks: bool
lines: List[str],
resolution_wh: Tuple[int, int],
with_masks: bool,
is_obb: bool = False,
) -> Detections:
if len(lines) == 0:
return Detections.empty()

class_id, relative_xyxy, relative_polygon = [], [], []
class_id, relative_xyxy, relative_polygon, relative_xyxyxyxy = [], [], [], []
w, h = resolution_wh
for line in lines:
values = line.split()
Expand All @@ -88,28 +92,38 @@ def yolo_annotations_to_detections(
elif len(values) > 5:
polygon = _parse_polygon(values=values[1:])
relative_xyxy.append(polygon_to_xyxy(polygon=polygon))
if is_obb:
relative_xyxyxyxy.append(np.array(values[1:]))
if with_masks:
relative_polygon.append(polygon)

class_id = np.array(class_id, dtype=int)
relative_xyxy = np.array(relative_xyxy, dtype=np.float32)
xyxy = relative_xyxy * np.array([w, h, w, h], dtype=np.float32)
data = {}

if is_obb:
relative_xyxyxyxy = np.array(relative_xyxyxyxy, dtype=np.float32)
xyxyxyxy = relative_xyxyxyxy.reshape(-1, 4, 2)
xyxyxyxy *= np.array([w, h], dtype=np.float32)
data[ORIENTED_BOX_COORDINATES] = xyxyxyxy

if not with_masks:
return Detections(class_id=class_id, xyxy=xyxy)
return Detections(class_id=class_id, xyxy=xyxy, data=data)

polygons = [
(polygon * np.array(resolution_wh)).astype(int) for polygon in relative_polygon
]
mask = _polygons_to_masks(polygons=polygons, resolution_wh=resolution_wh)
return Detections(class_id=class_id, xyxy=xyxy, mask=mask)
return Detections(class_id=class_id, xyxy=xyxy, data=data, mask=mask)


def load_yolo_annotations(
images_directory_path: str,
annotations_directory_path: str,
data_yaml_path: str,
force_masks: bool = False,
is_obb: bool = False,
) -> Tuple[List[str], Dict[str, np.ndarray], Dict[str, Detections]]:
"""
Loads YOLO annotations and returns class names, images,
Expand All @@ -123,6 +137,9 @@ def load_yolo_annotations(
YAML file containing class information.
force_masks (bool, optional): If True, forces masks to be loaded
for all annotations, regardless of whether they are present.
is_obb (bool, optional): If True, loads the annotations in OBB format.
OBB annotations are defined as `[class_id, x, y, x, y, x, y, x, y]`,
where pairs of [x, y] are box corners.
Returns:
Tuple[List[str], Dict[str, np.ndarray], Dict[str, Detections]]:
Expand Down Expand Up @@ -156,9 +173,11 @@ def load_yolo_annotations(
with_masks = _with_mask(lines=lines)
with_masks = force_masks if force_masks else with_masks
annotation = yolo_annotations_to_detections(
lines=lines, resolution_wh=resolution_wh, with_masks=with_masks
lines=lines,
resolution_wh=resolution_wh,
with_masks=with_masks,
is_obb=is_obb,
)

images[image_path] = image
annotations[image_path] = annotation
return classes, images, annotations
Expand Down
Loading

0 comments on commit a377b54

Please sign in to comment.