Repository: roboflow/supervision
File: supervision/detection/utils.py (Python)

Code before:
        import numpy as np
        import supervision as sv

        boxes = np.array([[10, 10, 20, 20], [30, 30, 40, 40]])
        offset = np.array([5, 5])
        moved_box = sv.move_boxes(boxes, offset)
        print(moved_box)
        # np.array([
        #    [15, 15, 25, 25],
        #     [35, 35, 45, 45]
        # ])
        ```
    """
    return xyxy + np.hstack([offset, offset])


def move_masks(
    masks: np.ndarray,
    offset: np.ndarray,
    resolution_wh: Tuple[int, int] = None,
) -> np.ndarray:
    """
    Offset the masks in an array by the specified (x, y) amount.

    Args:
        masks (np.ndarray): array of bools
        offset (np.ndarray): An array of shape `(2,)` containing non-negative int values
            `[dx, dy]`.
        resolution_wh (Tuple[int, int]): The width and height of the desired mask
            resolution.

    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}")

    mask_array = np.full((masks.shape[0], resolution_wh[1], resolution_wh[0]), False)
    mask_array[
        :,
        offset[1] : masks.shape[1] + offset[1],
        offset[0] : masks.shape[2] + offset[0],
    ] = masks

    return mask_array


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

Review comment (suggestion):
I'd make that `masks` docstring a bit more precise. Talk about shapes etc.

```
masks (np.ndarray): A 3D array of binary masks corresponding to the predictions.
    Shape: `(N, H, W)`, where N is the number of predictions, and H, W are the
    dimensions of each mask.
```

Code after:
            confidence.append(prediction["confidence"])
            masks.append(mask)
            if "tracker_id" in prediction:
                tracker_ids.append(prediction["tracker_id"])

    xyxy = np.array(xyxy) if len(xyxy) > 0 else np.empty((0, 4))
    confidence = np.array(confidence) if len(confidence) > 0 else np.empty(0)
    class_id = np.array(class_id).astype(int) if len(class_id) > 0 else np.empty(0)
    class_name = np.array(class_name) if len(class_name) > 0 else np.empty(0)
    masks = np.array(masks, dtype=bool) if len(masks) > 0 else None
    tracker_id = np.array(tracker_ids).astype(int) if len(tracker_ids) > 0 else None
    data = {CLASS_NAME_DATA_FIELD: class_name}

    return xyxy, confidence, class_id, masks, tracker_id, data


def move_boxes(xyxy: np.ndarray, offset: np.ndarray) -> np.ndarray:
    """
    Parameters:
        xyxy (np.ndarray): An array of shape `(n, 4)` containing the bounding boxes
            coordinates in format `[x1, y1, x2, y2]`
        offset (np.array): An array of shape `(2,)` containing offset values in format
            is `[dx, dy]`.

    Returns:
        np.ndarray: Repositioned bounding boxes.

    Example:
        ```python
        import numpy as np
        import supervision as sv

        boxes = np.array([[10, 10, 20, 20], [30, 30, 40, 40]])
        offset = np.array([5, 5])
        moved_box = sv.move_boxes(boxes, offset)
        print(moved_box)
        # np.array([
        #    [15, 15, 25, 25],
        #     [35, 35, 45, 45]
        # ])
        ```
    """
    return xyxy + np.hstack([offset, offset])


def move_masks(
    masks: np.ndarray,
    offset: np.ndarray,
    resolution_wh: Tuple[int, int] = None,
) -> np.ndarray:
    """