1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
- import warnings
- from typing import Tuple
- import numpy as np
- import torch
- from torch import Tensor
- from super_gradients.training.utils.bbox_formats.bbox_format import (
- BoundingBoxFormat,
- )
- __all__ = [
- "NormalizedXYXYCoordinateFormat",
- "normalized_xyxy_to_xyxy",
- "normalized_xyxy_to_xyxy_inplace",
- "xyxy_to_normalized_xyxy",
- "xyxy_to_normalized_xyxy_inplace",
- ]
- def normalized_xyxy_to_xyxy(bboxes, image_shape: Tuple[int, int]):
- """
- Convert unit-normalized XYXY bboxes to XYXY bboxes in pixel units.
- :param bboxes: BBoxes of shape (..., 4) in XYXY (unit-normalized) format
- :param image_shape: Image shape (rows,cols)
- :return: BBoxes of shape (..., 4) in XYXY (pixels) format
- """
- rows, cols = image_shape
- if torch.jit.is_scripting():
- scale = torch.tensor([cols, rows, cols, rows], dtype=bboxes.dtype, device=bboxes.device)
- scale = scale.reshape([1] * (len(bboxes.size()) - 1) + [4])
- else:
- if torch.is_tensor(bboxes):
- scale = torch.tensor([cols, rows, cols, rows], dtype=bboxes.dtype, device=bboxes.device)
- scale = scale.reshape([1] * (len(bboxes.size()) - 1) + [4])
- elif isinstance(bboxes, np.ndarray):
- scale = np.array([cols, rows, cols, rows], dtype=bboxes.dtype)
- scale = scale.reshape([1] * (len(bboxes.shape) - 1) + [4])
- else:
- raise RuntimeError(f"Only Torch tensor or Numpy array is supported. Received bboxes of type {str(type(bboxes))}")
- return bboxes * scale
- def xyxy_to_normalized_xyxy(bboxes: Tensor, image_shape: Tuple[int, int]) -> Tensor:
- """
- Convert bboxes from XYXY (pixels) format to XYXY (unit-normalized) format
- :param bboxes: BBoxes of shape (..., 4) in XYXY (pixels) format
- :param image_shape: Image shape (rows,cols)
- :return: BBoxes of shape (..., 4) in XYXY (unit-normalized) format
- """
- rows, cols = image_shape
- if torch.jit.is_scripting():
- scale = torch.tensor([cols, rows, cols, rows], dtype=bboxes.dtype, device=bboxes.device)
- scale = scale.reshape([1] * (len(bboxes.size()) - 1) + [4])
- else:
- if torch.is_tensor(bboxes):
- scale = torch.tensor([cols, rows, cols, rows], dtype=bboxes.dtype, device=bboxes.device)
- scale = scale.reshape([1] * (len(bboxes.size()) - 1) + [4])
- elif isinstance(bboxes, np.ndarray):
- scale = np.array([cols, rows, cols, rows], dtype=bboxes.dtype)
- else:
- raise RuntimeError(f"Only Torch tensor or Numpy array is supported. Received bboxes of type {str(type(bboxes))}")
- return bboxes / scale
- def normalized_xyxy_to_xyxy_inplace(bboxes, image_shape: Tuple[int, int]):
- """
- Convert unit-normalized XYXY bboxes to XYXY bboxes in pixel units. This function operates in-place.
- :param bboxes: BBoxes of shape (..., 4) in XYXY (unit-normalized) format
- :param image_shape: Image shape (rows,cols)
- :return: BBoxes of shape (..., 4) in XYXY (pixels) format
- """
- rows, cols = image_shape
- bboxes[..., 0:3:2] *= cols
- bboxes[..., 1:4:2] *= rows
- return bboxes
- def xyxy_to_normalized_xyxy_inplace(bboxes, image_shape: Tuple[int, int]):
- """
- Convert bboxes from XYXY (pixels) format to XYXY (unit-normalized) format. This function operates in-place.
- :param bboxes: BBoxes of shape (..., 4) in XYXY (pixels) format
- :param image_shape: Image shape (rows,cols)
- :return: BBoxes of shape (..., 4) in XYXY (unit-normalized) format
- """
- if not torch.jit.is_scripting():
- if torch.is_tensor(bboxes) and not torch.is_floating_point(bboxes):
- warnings.warn(
- f"Detected non floating-point ({bboxes.dtype}) input to xyxy_to_normalized_xyxy_inplace function. "
- f"This may cause rounding errors and lose of precision. You may want to convert your array to floating-point precision first."
- )
- if isinstance(bboxes, np.ndarray) and not np.issubdtype(bboxes.dtype, np.floating):
- warnings.warn(
- f"Detected non floating-point input ({bboxes.dtype}) to xyxy_to_normalized_xyxy_inplace function. "
- f"This may cause rounding errors and lose of precision. You may want to convert your array to floating-point precision first."
- )
- rows, cols = image_shape
- bboxes[..., 0:3:2] /= cols
- bboxes[..., 1:4:2] /= rows
- return bboxes
- class NormalizedXYXYCoordinateFormat(BoundingBoxFormat):
- """
- Normalized X1,Y1,X2,Y2 bounding boxes format
- """
- def __init__(self):
- super().__init__()
- self.format = "normalized_xyxy"
- self.normalized = True
- def get_to_xyxy(self, inplace: bool):
- if inplace:
- return normalized_xyxy_to_xyxy_inplace
- else:
- return normalized_xyxy_to_xyxy
- def get_from_xyxy(self, inplace: bool):
- if inplace:
- return xyxy_to_normalized_xyxy_inplace
- else:
- return xyxy_to_normalized_xyxy
|