Skip to content

box

data.dataclass.box

boxes_datas module-attribute

boxes_datas = {'xyxy': [[1, 2, 4, 6], [22, 28, 36, 62], [13, 39, 14, 78], [42, 24, 81, 46]], 'xywh': [[1, 2, 3, 4], [22, 28, 14, 34], [13, 39, 1, 39], [42, 24, 39, 22]], 'ccwh': [[2.5, 4, 3, 4], [29, 45, 14, 34], [13.5, 58.5, 1, 39], [61.5, 35, 39, 22]]}

boxes module-attribute

boxes = test_init_box(box_data, coordinate)

NumpyBoxes

Bases: ndarray

coordinate instance-attribute

coordinate: str

__new__

__new__(input_array, coordinate: str, dtype=None) -> NumpyBoxes
Source code in SaigeToolkit/data/dataclass/box.py
def __new__(cls, input_array, coordinate: str, dtype=None) -> NumpyBoxes:
    obj = np.array(input_array).view(cls)

    cls._check_boxes(obj)

    if dtype is not None:
        obj = obj.astype(dtype)
    obj.coordinate = coordinate
    return obj

__array_finalize__

__array_finalize__(obj)
Source code in SaigeToolkit/data/dataclass/box.py
def __array_finalize__(self, obj):
    if obj is None:
        return
    self.coordinate = getattr(obj, "coordinate", None)

__array_function__

__array_function__(func, types, args, kwargs)
Source code in SaigeToolkit/data/dataclass/box.py
def __array_function__(self, func, types, args, kwargs):
    def unwrap(e):
        return np.asarray(e) if isinstance(e, NumpyBoxes) else e

    def wrap(e, coordinate):
        return NumpyBoxes(e, coordinate) if isinstance(e, np.ndarray) else e

    def get_coordinate(args, kwargs):
        flat_args, _ = tree_flatten(args)
        flat_kwargs, _ = tree_flatten(kwargs)
        coordinates = [e.coordinate for e in flat_args + flat_kwargs if isinstance(e, NumpyBoxes)]

        assert len(set(coordinates)) == 1
        coordinate = coordinates[0]

        return coordinate

    kwargs = kwargs or {}
    ret = func(*tree_map(unwrap, args), **tree_map(unwrap, kwargs))
    coordinate = get_coordinate(args, kwargs)
    wrap_with_coordinate = functools.partial(wrap, coordinate=coordinate)
    ret = tree_map(wrap_with_coordinate, ret)

    return ret

convert_coordinate

convert_coordinate(coordinate: str) -> NumpyBoxes
Source code in SaigeToolkit/data/dataclass/box.py
def convert_coordinate(self, coordinate: str) -> NumpyBoxes:
    new_boxes: NumpyBoxes = convert_coordinate(self, self.coordinate, coordinate)
    new_boxes.coordinate = coordinate
    return new_boxes

to_numpy

to_numpy() -> ndarray
Source code in SaigeToolkit/data/dataclass/box.py
def to_numpy(self) -> np.ndarray:
    return np.array(self)

to_tensor

to_tensor() -> Tensor
Source code in SaigeToolkit/data/dataclass/box.py
def to_tensor(self) -> torch.Tensor:
    return torch.from_numpy(self.to_numpy())

_check_boxes staticmethod

_check_boxes(boxes: ndarray)
Source code in SaigeToolkit/data/dataclass/box.py
@staticmethod
def _check_boxes(boxes: np.ndarray):
    # 숫자가 아닌 값이 들어오는 경우
    if not np.issubdtype(boxes.dtype, np.number):
        raise BoxValueError

    # box position이 음수가 들어오는 경우
    if np.any(boxes < 0):
        raise BoxValueError

convert_coordinate

convert_coordinate(boxes: Union[ndarray, Tensor], source_coordinate: str, target_coordinate: str) -> Union[ndarray, Tensor]
Source code in SaigeToolkit/data/dataclass/box.py
def convert_coordinate(
    boxes: Union[np.ndarray, torch.Tensor],  # shape: (num_bboxes, 4), dtype: float
    source_coordinate: str,  # coordinate type of input boxes ["xyxy", "xywh", "ccwh"]
    target_coordinate: str,  # coordinate type want to convert ["xyxy", "xywh", "ccwh"]
) -> Union[np.ndarray, torch.Tensor]:
    def _to_xywh(boxes: NumpyBoxes, coordinate: str) -> NumpyBoxes:
        """some coordinate -> (left, top, width, height)"""
        if coordinate == "xywh":
            pass
        elif coordinate == "xyxy":
            boxes[:, [2, 3]] = boxes[:, [2, 3]] - boxes[:, [0, 1]]
        elif coordinate == "ccwh":
            boxes[:, [0, 1]] = boxes[:, [0, 1]] - (boxes[:, [2, 3]] / 2)
        else:
            raise NotImplementedError

        return boxes

    def _from_xywh(boxes: NumpyBoxes, coordinate: str) -> NumpyBoxes:
        """(left, top, width, height) -> some coordinate"""
        if coordinate == "xywh":
            pass
        elif coordinate == "xyxy":
            boxes[:, [2, 3]] = boxes[:, [2, 3]] + boxes[:, [0, 1]]
        elif coordinate == "ccwh":
            boxes[:, [0, 1]] = boxes[:, [0, 1]] + (boxes[:, [2, 3]] / 2)
        else:
            raise NotImplementedError

        return boxes

    if isinstance(boxes, np.ndarray):
        new_boxes = boxes.copy()
    elif isinstance(boxes, torch.Tensor):
        new_boxes = boxes.clone()

    if source_coordinate != target_coordinate:  # if you want to change the coordinate
        new_boxes = _to_xywh(new_boxes, source_coordinate)  # source coordinate -> xywh
        new_boxes = _from_xywh(new_boxes, target_coordinate)  # xywh -> target coordinate

    return new_boxes

test_init_box

test_init_box(box_data, coordinate) -> NumpyBoxes
Source code in SaigeToolkit/data/dataclass/box.py
def test_init_box(box_data, coordinate) -> NumpyBoxes:
    boxes = NumpyBoxes(box_data, coordinate)

    assert boxes.coordinate == coordinate
    assert boxes.dtype == np.float32
    assert boxes.tolist() == box_data

    return boxes

test_base_function

test_base_function(boxes: NumpyBoxes)
Source code in SaigeToolkit/data/dataclass/box.py
def test_base_function(boxes: NumpyBoxes):
    boxes = boxes + 3
    boxes = boxes * 3
    boxes = boxes - 3
    boxes = boxes / 3
    boxes = np.concatenate([boxes] * 4, axis=0)
    boxes = np.split(boxes, 4, axis=0)[0]
    boxes = boxes.astype(np.int32)

    assert boxes.dtype == np.int32

test_convert_coordinate

test_convert_coordinate(boxes: NumpyBoxes, coordinate, answer)
Source code in SaigeToolkit/data/dataclass/box.py
def test_convert_coordinate(boxes: NumpyBoxes, coordinate, answer):
    boxes = boxes.convert_coordinate(coordinate)

    assert boxes.coordinate == coordinate
    assert boxes.dtype == np.float32
    assert boxes.tolist() == answer

test_to_other_data

test_to_other_data(boxes: NumpyBoxes, answer)
Source code in SaigeToolkit/data/dataclass/box.py
def test_to_other_data(boxes: NumpyBoxes, answer):
    new_boxes = boxes.to_tensor()

    assert new_boxes.tolist() == answer