Merge pull request #2016 from roboflow/feature/make_box_aspect_ratio_part_of_detections_api

add `box_aspect_ratio` property to `sv.Detections`
This commit is contained in:
Piotr Skalski authored and GitHub committed 2025-11-16 13:39:49 +01:00
commit 6119f2017e
4 files changed
+38 -53

No files matched your search

-2
View File
@@ -52,7 +52,6 @@ from supervision.detection.tools.json_sink import JSONSink
from supervision.detection.tools.polygon_zone import PolygonZone, PolygonZoneAnnotator
from supervision.detection.tools.smoother import DetectionsSmoother
from supervision.detection.utils.boxes import (
box_aspect_ratio,
clip_boxes,
denormalize_boxes,
move_boxes,
@@ -200,7 +199,6 @@ __all__ = [
"VideoInfo",
"VideoSink",
"approximate_polygon",
"box_aspect_ratio",
"box_iou",
"box_iou_batch",
"box_iou_batch_with_jaccard",
+37
View File
@@ -2088,6 +2088,43 @@ class Detections:
"""
return (self.xyxy[:, 3] - self.xyxy[:, 1]) * (self.xyxy[:, 2] - self.xyxy[:, 0])
@property
def box_aspect_ratio(self) -> np.ndarray:
"""
Compute the aspect ratio (width divided by height) for each bounding box.
Returns:
np.ndarray: Array of shape `(N,)` containing aspect ratios, where `N` is the
number of boxes (width / height for each box).
Examples:
```python
import numpy as np
import supervision as sv
xyxy = np.array([
[10, 10, 50, 50],
[60, 10, 180, 50],
[10, 60, 50, 180],
])
detections = sv.Detections(xyxy=xyxy)
detections.box_aspect_ratio
# array([1.0, 3.0, 0.33333333])
ar = detections.box_aspect_ratio
detections[(ar < 2.0) & (ar > 0.5)].xyxy
# array([[10., 10., 50., 50.]])
```
"""
widths = self.xyxy[:, 2] - self.xyxy[:, 0]
heights = self.xyxy[:, 3] - self.xyxy[:, 1]
aspect_ratios = np.full_like(widths, np.nan, dtype=np.float64)
np.divide(widths, heights, out=aspect_ratios, where=heights != 0)
return aspect_ratios
def with_nms(
self,
threshold: float = 0.5,
-51
View File
@@ -6,57 +6,6 @@ import numpy.typing as npt
from supervision.detection.utils.iou_and_nms import box_iou_batch
def box_aspect_ratio(xyxy: np.ndarray) -> np.ndarray:
"""
Calculate aspect ratios of bounding boxes given in xyxy format.
Computes the width divided by height for each bounding box. Returns NaN
for boxes with zero height to avoid division errors.
Args:
xyxy (`numpy.ndarray`): Array of bounding boxes in
`(x_min, y_min, x_max, y_max)` format with shape `(N, 4)`.
Returns:
`numpy.ndarray`: Array of aspect ratios with shape `(N,)`, where each element is
the width divided by height of a box. Elements are NaN if height is zero.
Examples:
```python
import numpy as np
import supervision as sv
xyxy = np.array([
[10, 20, 30, 50],
[0, 0, 40, 10],
])
sv.box_aspect_ratio(xyxy)
# array([0.66666667, 4. ])
xyxy = np.array([
[10, 10, 30, 10],
[5, 5, 25, 25],
])
sv.box_aspect_ratio(xyxy)
# array([ nan, 1. ])
```
"""
widths = xyxy[:, 2] - xyxy[:, 0]
heights = xyxy[:, 3] - xyxy[:, 1]
aspect_ratios = np.full_like(widths, np.nan, dtype=np.float64)
np.divide(
widths,
heights,
out=aspect_ratios,
where=heights != 0,
)
return aspect_ratios
def clip_boxes(xyxy: np.ndarray, resolution_wh: tuple[int, int]) -> np.ndarray:
"""
Clips bounding boxes coordinates to fit within the frame resolution.
+1
View File
@@ -145,6 +145,7 @@ class MockDataclass:
"metadata",
"area",
"box_area",
"box_aspect_ratio",
},
DoesNotRaise(),
),