Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/inference slicer segmentation #1178

Merged
merged 11 commits into from
May 13, 2024
18 changes: 14 additions & 4 deletions supervision/detection/tools/inference_slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@
import numpy as np

from supervision.detection.core import Detections
from supervision.detection.utils import move_boxes
from supervision.detection.utils import move_boxes, move_masks
from supervision.utils.image import crop_image


def move_detections(detections: Detections, offset: np.array) -> Detections:
def move_detections(
detections: Detections, offset: np.ndarray, image_shape: np.ndarray
Copy link
Collaborator

Choose a reason for hiding this comment

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

Argument image_shape is called resolution_wh in most places in supervision. Let's keep it this way.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, I think it should be Optional.

) -> Detections:
"""
Args:
detections (sv.Detections): Detections object to be moved.
offset (np.array): An array of shape `(2,)` containing offset values in format
offset (np.ndarray): An array of shape `(2,)` containing offset values in format
is `[dx, dy]`.
image_size (np.ndarray): An array of shape `(2,)` or `(3,)`, size of the image
is in format `[width, height]`.
Returns:
(sv.Detections) repositioned Detections object.
"""
detections.xyxy = move_boxes(xyxy=detections.xyxy, offset=offset)
if detections.mask is not None:
detections.mask = move_masks(
masks=detections.mask, offset=offset, desired_shape=image_shape
)
return detections


Expand Down Expand Up @@ -126,7 +134,9 @@ def _run_callback(self, image, offset) -> Detections:
"""
image_slice = crop_image(image=image, xyxy=offset)
detections = self.callback(image_slice)
detections = move_detections(detections=detections, offset=offset[:2])
detections = move_detections(
detections=detections, offset=offset[:2], image_shape=image.shape
)

return detections

Expand Down
40 changes: 40 additions & 0 deletions supervision/detection/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,46 @@ def move_boxes(xyxy: np.ndarray, offset: np.ndarray) -> np.ndarray:
return xyxy + np.hstack([offset, offset])


def move_masks(
masks: np.ndarray, offset: np.ndarray, desired_shape: Optional[np.ndarray] = None
LinasKo marked this conversation as resolved.
Show resolved Hide resolved
) -> np.ndarray:
"""
Offset the masks in an array by the specified (x, y) amount.

Note the axis orders:

- `masks`: array of shape `(n, y, x)`
- `offset`: array of ints: `(x, y)`
- `desired_shape`: array of ints, shaped `(y, x, ...)`

Args:
masks (np.ndarray): array of bools
LinasKo marked this conversation as resolved.
Show resolved Hide resolved
offset (np.ndarray): An array of shape `(2,)` containing non-negative int values
`[dx, dy]`.
desired_shape (np.ndarray, optional): Final shape of the mask in the format
`(height, width, ...)`. If provided, the masks will be padded to match this
shape. Note the axis order (y,x)!

Returns:
(np.ndarray) repositioned masks, optionally padded to the specified shape.
"""
if offset[0] < 0 or offset[1] < 0:
raise ValueError(f"Offset values must be non-negative integers. Got: {offset}")

size_x, size_y = masks.shape[1:] + offset[::-1]
if desired_shape is not None:
size_y, size_x = desired_shape[:2]

mask_arr = np.full((masks.shape[0], size_y, size_x), False)
LinasKo marked this conversation as resolved.
Show resolved Hide resolved
mask_arr[
:,
offset[1] : masks.shape[1] + offset[1],
offset[0] : masks.shape[2] + offset[0],
] = masks

return mask_arr


def scale_boxes(xyxy: np.ndarray, factor: float) -> np.ndarray:
"""
Scale the dimensions of bounding boxes.
Expand Down