segment-everything 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- segment_everything/__init__.py +5 -0
- segment_everything/augmentation/albumentations_helper.py +0 -0
- segment_everything/detect_and_segment.py +131 -0
- segment_everything/napari_helper.py +15 -0
- segment_everything/prompt_generator.py +188 -0
- segment_everything/py.typed +5 -0
- segment_everything/stacked_label_dataset.py +113 -0
- segment_everything/stacked_labels.py +428 -0
- segment_everything/vendored/PromptGuidedDecoder/Prompt_guided_Mask_Decoder.pt +0 -0
- segment_everything/vendored/__init__.py +5 -0
- segment_everything/vendored/dice.py +158 -0
- segment_everything/vendored/efficientvit/__init__.py +0 -0
- segment_everything/vendored/efficientvit/apps/__init__.py +0 -0
- segment_everything/vendored/efficientvit/apps/data_provider/__init__.py +7 -0
- segment_everything/vendored/efficientvit/apps/data_provider/augment/__init__.py +6 -0
- segment_everything/vendored/efficientvit/apps/data_provider/augment/bbox.py +30 -0
- segment_everything/vendored/efficientvit/apps/data_provider/augment/color_aug.py +78 -0
- segment_everything/vendored/efficientvit/apps/data_provider/base.py +254 -0
- segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/__init__.py +6 -0
- segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/_data_loader.py +1538 -0
- segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/_data_worker.py +357 -0
- segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/controller.py +100 -0
- segment_everything/vendored/efficientvit/apps/setup.py +150 -0
- segment_everything/vendored/efficientvit/apps/trainer/__init__.py +6 -0
- segment_everything/vendored/efficientvit/apps/trainer/base.py +318 -0
- segment_everything/vendored/efficientvit/apps/trainer/run_config.py +129 -0
- segment_everything/vendored/efficientvit/apps/utils/__init__.py +12 -0
- segment_everything/vendored/efficientvit/apps/utils/dist.py +32 -0
- segment_everything/vendored/efficientvit/apps/utils/ema.py +52 -0
- segment_everything/vendored/efficientvit/apps/utils/export.py +45 -0
- segment_everything/vendored/efficientvit/apps/utils/init.py +66 -0
- segment_everything/vendored/efficientvit/apps/utils/lr.py +52 -0
- segment_everything/vendored/efficientvit/apps/utils/metric.py +43 -0
- segment_everything/vendored/efficientvit/apps/utils/misc.py +101 -0
- segment_everything/vendored/efficientvit/apps/utils/opt.py +28 -0
- segment_everything/vendored/efficientvit/cls_model_zoo.py +79 -0
- segment_everything/vendored/efficientvit/clscore/__init__.py +0 -0
- segment_everything/vendored/efficientvit/clscore/data_provider/__init__.py +5 -0
- segment_everything/vendored/efficientvit/clscore/data_provider/imagenet.py +142 -0
- segment_everything/vendored/efficientvit/clscore/trainer/__init__.py +6 -0
- segment_everything/vendored/efficientvit/clscore/trainer/cls_run_config.py +18 -0
- segment_everything/vendored/efficientvit/clscore/trainer/cls_trainer.py +265 -0
- segment_everything/vendored/efficientvit/clscore/trainer/utils/__init__.py +7 -0
- segment_everything/vendored/efficientvit/clscore/trainer/utils/label_smooth.py +18 -0
- segment_everything/vendored/efficientvit/clscore/trainer/utils/metric.py +23 -0
- segment_everything/vendored/efficientvit/clscore/trainer/utils/mixup.py +67 -0
- segment_everything/vendored/efficientvit/models/__init__.py +0 -0
- segment_everything/vendored/efficientvit/models/efficientvit/__init__.py +8 -0
- segment_everything/vendored/efficientvit/models/efficientvit/backbone.py +380 -0
- segment_everything/vendored/efficientvit/models/efficientvit/cls.py +188 -0
- segment_everything/vendored/efficientvit/models/efficientvit/sam.py +181 -0
- segment_everything/vendored/efficientvit/models/efficientvit/seg.py +373 -0
- segment_everything/vendored/efficientvit/models/nn/__init__.py +8 -0
- segment_everything/vendored/efficientvit/models/nn/act.py +30 -0
- segment_everything/vendored/efficientvit/models/nn/drop.py +104 -0
- segment_everything/vendored/efficientvit/models/nn/norm.py +164 -0
- segment_everything/vendored/efficientvit/models/nn/ops.py +597 -0
- segment_everything/vendored/efficientvit/models/utils/__init__.py +7 -0
- segment_everything/vendored/efficientvit/models/utils/list.py +53 -0
- segment_everything/vendored/efficientvit/models/utils/network.py +73 -0
- segment_everything/vendored/efficientvit/models/utils/random.py +65 -0
- segment_everything/vendored/efficientvit/sam_model_zoo.py +45 -0
- segment_everything/vendored/efficientvit/seg_model_zoo.py +70 -0
- segment_everything/vendored/get_object_aware.py +26 -0
- segment_everything/vendored/mobilesamv2/__init__.py +16 -0
- segment_everything/vendored/mobilesamv2/automatic_mask_generator.py +415 -0
- segment_everything/vendored/mobilesamv2/build_sam.py +246 -0
- segment_everything/vendored/mobilesamv2/modeling/__init__.py +11 -0
- segment_everything/vendored/mobilesamv2/modeling/common.py +43 -0
- segment_everything/vendored/mobilesamv2/modeling/image_encoder.py +394 -0
- segment_everything/vendored/mobilesamv2/modeling/mask_decoder.py +213 -0
- segment_everything/vendored/mobilesamv2/modeling/prompt_encoder.py +217 -0
- segment_everything/vendored/mobilesamv2/modeling/sam.py +203 -0
- segment_everything/vendored/mobilesamv2/modeling/transformer.py +240 -0
- segment_everything/vendored/mobilesamv2/predictor.py +384 -0
- segment_everything/vendored/mobilesamv2/utils/__init__.py +5 -0
- segment_everything/vendored/mobilesamv2/utils/amg.py +347 -0
- segment_everything/vendored/mobilesamv2/utils/onnx.py +144 -0
- segment_everything/vendored/mobilesamv2/utils/transforms.py +103 -0
- segment_everything/vendored/object_detection/__init__.py +0 -0
- segment_everything/vendored/object_detection/ultralytics/__init__.py +5 -0
- segment_everything/vendored/object_detection/ultralytics/nn/__init__.py +9 -0
- segment_everything/vendored/object_detection/ultralytics/nn/autobackend.py +658 -0
- segment_everything/vendored/object_detection/ultralytics/nn/autoshape.py +397 -0
- segment_everything/vendored/object_detection/ultralytics/nn/modules/__init__.py +110 -0
- segment_everything/vendored/object_detection/ultralytics/nn/modules/block.py +304 -0
- segment_everything/vendored/object_detection/ultralytics/nn/modules/conv.py +297 -0
- segment_everything/vendored/object_detection/ultralytics/nn/modules/head.py +468 -0
- segment_everything/vendored/object_detection/ultralytics/nn/modules/transformer.py +378 -0
- segment_everything/vendored/object_detection/ultralytics/nn/modules/utils.py +78 -0
- segment_everything/vendored/object_detection/ultralytics/nn/tasks.py +1049 -0
- segment_everything/vendored/object_detection/ultralytics/prompt_mobilesamv2/__init__.py +6 -0
- segment_everything/vendored/object_detection/ultralytics/prompt_mobilesamv2/model.py +104 -0
- segment_everything/vendored/object_detection/ultralytics/prompt_mobilesamv2/predict.py +95 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/__init__.py +5 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/cfg/__init__.py +588 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/cfg/default.yaml +117 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/__init__.py +9 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/annotator.py +53 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/augment.py +899 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/base.py +286 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/build.py +213 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/converter.py +358 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/dataloaders/__init__.py +0 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/dataloaders/stream_loaders.py +459 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/dataset.py +274 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/dataset_wrappers.py +53 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/download_weights.sh +18 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/get_coco.sh +60 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/get_coco128.sh +17 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/get_imagenet.sh +51 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/data/utils.py +716 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/engine/__init__.py +0 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/engine/exporter.py +1214 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/engine/model.py +641 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/engine/predictor.py +461 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/engine/results.py +741 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/__init__.py +893 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/autobatch.py +108 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/callbacks/__init__.py +5 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/callbacks/base.py +212 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/checks.py +547 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/dist.py +67 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/downloads.py +353 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/errors.py +12 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/files.py +100 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/instance.py +391 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/loss.py +579 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/metrics.py +1189 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/ops.py +870 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/patches.py +45 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/plotting.py +767 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/tal.py +276 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/torch_utils.py +684 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/utils/tuner.py +54 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/v8/__init__.py +5 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/v8/detect/__init__.py +5 -0
- segment_everything/vendored/object_detection/ultralytics/yolo/v8/detect/predict.py +69 -0
- segment_everything/vendored/tinyvit/__init__.py +2 -0
- segment_everything/vendored/tinyvit/tiny_vit.py +867 -0
- segment_everything/weights_helper.py +124 -0
- segment_everything-0.1.0.dist-info/METADATA +53 -0
- segment_everything-0.1.0.dist-info/RECORD +145 -0
- segment_everything-0.1.0.dist-info/WHEEL +4 -0
- segment_everything-0.1.0.dist-info/licenses/LICENSE +28 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# Ultralytics YOLO 🚀, AGPL-3.0 license
|
|
2
|
+
|
|
3
|
+
from collections import abc
|
|
4
|
+
from itertools import repeat
|
|
5
|
+
from numbers import Number
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from .ops import ltwh2xywh, ltwh2xyxy, resample_segments, xywh2ltwh, xywh2xyxy, xyxy2ltwh, xyxy2xywh
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _ntuple(n):
|
|
14
|
+
"""From PyTorch internals."""
|
|
15
|
+
|
|
16
|
+
def parse(x):
|
|
17
|
+
"""Parse bounding boxes format between XYWH and LTWH."""
|
|
18
|
+
return x if isinstance(x, abc.Iterable) else tuple(repeat(x, n))
|
|
19
|
+
|
|
20
|
+
return parse
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
to_4tuple = _ntuple(4)
|
|
24
|
+
|
|
25
|
+
# `xyxy` means left top and right bottom
|
|
26
|
+
# `xywh` means center x, center y and width, height(yolo format)
|
|
27
|
+
# `ltwh` means left top and width, height(coco format)
|
|
28
|
+
_formats = ['xyxy', 'xywh', 'ltwh']
|
|
29
|
+
|
|
30
|
+
__all__ = 'Bboxes', # tuple or list
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Bboxes:
|
|
34
|
+
"""Now only numpy is supported."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, bboxes, format='xyxy') -> None:
|
|
37
|
+
assert format in _formats, f'Invalid bounding box format: {format}, format must be one of {_formats}'
|
|
38
|
+
bboxes = bboxes[None, :] if bboxes.ndim == 1 else bboxes
|
|
39
|
+
assert bboxes.ndim == 2
|
|
40
|
+
assert bboxes.shape[1] == 4
|
|
41
|
+
self.bboxes = bboxes
|
|
42
|
+
self.format = format
|
|
43
|
+
# self.normalized = normalized
|
|
44
|
+
|
|
45
|
+
# def convert(self, format):
|
|
46
|
+
# assert format in _formats
|
|
47
|
+
# if self.format == format:
|
|
48
|
+
# bboxes = self.bboxes
|
|
49
|
+
# elif self.format == "xyxy":
|
|
50
|
+
# if format == "xywh":
|
|
51
|
+
# bboxes = xyxy2xywh(self.bboxes)
|
|
52
|
+
# else:
|
|
53
|
+
# bboxes = xyxy2ltwh(self.bboxes)
|
|
54
|
+
# elif self.format == "xywh":
|
|
55
|
+
# if format == "xyxy":
|
|
56
|
+
# bboxes = xywh2xyxy(self.bboxes)
|
|
57
|
+
# else:
|
|
58
|
+
# bboxes = xywh2ltwh(self.bboxes)
|
|
59
|
+
# else:
|
|
60
|
+
# if format == "xyxy":
|
|
61
|
+
# bboxes = ltwh2xyxy(self.bboxes)
|
|
62
|
+
# else:
|
|
63
|
+
# bboxes = ltwh2xywh(self.bboxes)
|
|
64
|
+
#
|
|
65
|
+
# return Bboxes(bboxes, format)
|
|
66
|
+
|
|
67
|
+
def convert(self, format):
|
|
68
|
+
"""Converts bounding box format from one type to another."""
|
|
69
|
+
assert format in _formats, f'Invalid bounding box format: {format}, format must be one of {_formats}'
|
|
70
|
+
if self.format == format:
|
|
71
|
+
return
|
|
72
|
+
elif self.format == 'xyxy':
|
|
73
|
+
bboxes = xyxy2xywh(self.bboxes) if format == 'xywh' else xyxy2ltwh(self.bboxes)
|
|
74
|
+
elif self.format == 'xywh':
|
|
75
|
+
bboxes = xywh2xyxy(self.bboxes) if format == 'xyxy' else xywh2ltwh(self.bboxes)
|
|
76
|
+
else:
|
|
77
|
+
bboxes = ltwh2xyxy(self.bboxes) if format == 'xyxy' else ltwh2xywh(self.bboxes)
|
|
78
|
+
self.bboxes = bboxes
|
|
79
|
+
self.format = format
|
|
80
|
+
|
|
81
|
+
def areas(self):
|
|
82
|
+
"""Return box areas."""
|
|
83
|
+
self.convert('xyxy')
|
|
84
|
+
return (self.bboxes[:, 2] - self.bboxes[:, 0]) * (self.bboxes[:, 3] - self.bboxes[:, 1])
|
|
85
|
+
|
|
86
|
+
# def denormalize(self, w, h):
|
|
87
|
+
# if not self.normalized:
|
|
88
|
+
# return
|
|
89
|
+
# assert (self.bboxes <= 1.0).all()
|
|
90
|
+
# self.bboxes[:, 0::2] *= w
|
|
91
|
+
# self.bboxes[:, 1::2] *= h
|
|
92
|
+
# self.normalized = False
|
|
93
|
+
#
|
|
94
|
+
# def normalize(self, w, h):
|
|
95
|
+
# if self.normalized:
|
|
96
|
+
# return
|
|
97
|
+
# assert (self.bboxes > 1.0).any()
|
|
98
|
+
# self.bboxes[:, 0::2] /= w
|
|
99
|
+
# self.bboxes[:, 1::2] /= h
|
|
100
|
+
# self.normalized = True
|
|
101
|
+
|
|
102
|
+
def mul(self, scale):
|
|
103
|
+
"""
|
|
104
|
+
Args:
|
|
105
|
+
scale (tuple | list | int): the scale for four coords.
|
|
106
|
+
"""
|
|
107
|
+
if isinstance(scale, Number):
|
|
108
|
+
scale = to_4tuple(scale)
|
|
109
|
+
assert isinstance(scale, (tuple, list))
|
|
110
|
+
assert len(scale) == 4
|
|
111
|
+
self.bboxes[:, 0] *= scale[0]
|
|
112
|
+
self.bboxes[:, 1] *= scale[1]
|
|
113
|
+
self.bboxes[:, 2] *= scale[2]
|
|
114
|
+
self.bboxes[:, 3] *= scale[3]
|
|
115
|
+
|
|
116
|
+
def add(self, offset):
|
|
117
|
+
"""
|
|
118
|
+
Args:
|
|
119
|
+
offset (tuple | list | int): the offset for four coords.
|
|
120
|
+
"""
|
|
121
|
+
if isinstance(offset, Number):
|
|
122
|
+
offset = to_4tuple(offset)
|
|
123
|
+
assert isinstance(offset, (tuple, list))
|
|
124
|
+
assert len(offset) == 4
|
|
125
|
+
self.bboxes[:, 0] += offset[0]
|
|
126
|
+
self.bboxes[:, 1] += offset[1]
|
|
127
|
+
self.bboxes[:, 2] += offset[2]
|
|
128
|
+
self.bboxes[:, 3] += offset[3]
|
|
129
|
+
|
|
130
|
+
def __len__(self):
|
|
131
|
+
"""Return the number of boxes."""
|
|
132
|
+
return len(self.bboxes)
|
|
133
|
+
|
|
134
|
+
@classmethod
|
|
135
|
+
def concatenate(cls, boxes_list: List['Bboxes'], axis=0) -> 'Bboxes':
|
|
136
|
+
"""
|
|
137
|
+
Concatenate a list of Bboxes objects into a single Bboxes object.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
boxes_list (List[Bboxes]): A list of Bboxes objects to concatenate.
|
|
141
|
+
axis (int, optional): The axis along which to concatenate the bounding boxes.
|
|
142
|
+
Defaults to 0.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Bboxes: A new Bboxes object containing the concatenated bounding boxes.
|
|
146
|
+
|
|
147
|
+
Note:
|
|
148
|
+
The input should be a list or tuple of Bboxes objects.
|
|
149
|
+
"""
|
|
150
|
+
assert isinstance(boxes_list, (list, tuple))
|
|
151
|
+
if not boxes_list:
|
|
152
|
+
return cls(np.empty(0))
|
|
153
|
+
assert all(isinstance(box, Bboxes) for box in boxes_list)
|
|
154
|
+
|
|
155
|
+
if len(boxes_list) == 1:
|
|
156
|
+
return boxes_list[0]
|
|
157
|
+
return cls(np.concatenate([b.bboxes for b in boxes_list], axis=axis))
|
|
158
|
+
|
|
159
|
+
def __getitem__(self, index) -> 'Bboxes':
|
|
160
|
+
"""
|
|
161
|
+
Retrieve a specific bounding box or a set of bounding boxes using indexing.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
index (int, slice, or np.ndarray): The index, slice, or boolean array to select
|
|
165
|
+
the desired bounding boxes.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Bboxes: A new Bboxes object containing the selected bounding boxes.
|
|
169
|
+
|
|
170
|
+
Raises:
|
|
171
|
+
AssertionError: If the indexed bounding boxes do not form a 2-dimensional matrix.
|
|
172
|
+
|
|
173
|
+
Note:
|
|
174
|
+
When using boolean indexing, make sure to provide a boolean array with the same
|
|
175
|
+
length as the number of bounding boxes.
|
|
176
|
+
"""
|
|
177
|
+
if isinstance(index, int):
|
|
178
|
+
return Bboxes(self.bboxes[index].view(1, -1))
|
|
179
|
+
b = self.bboxes[index]
|
|
180
|
+
assert b.ndim == 2, f'Indexing on Bboxes with {index} failed to return a matrix!'
|
|
181
|
+
return Bboxes(b)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class Instances:
|
|
185
|
+
|
|
186
|
+
def __init__(self, bboxes, segments=None, keypoints=None, bbox_format='xywh', normalized=True) -> None:
|
|
187
|
+
"""
|
|
188
|
+
Args:
|
|
189
|
+
bboxes (ndarray): bboxes with shape [N, 4].
|
|
190
|
+
segments (list | ndarray): segments.
|
|
191
|
+
keypoints (ndarray): keypoints(x, y, visible) with shape [N, 17, 3].
|
|
192
|
+
"""
|
|
193
|
+
if segments is None:
|
|
194
|
+
segments = []
|
|
195
|
+
self._bboxes = Bboxes(bboxes=bboxes, format=bbox_format)
|
|
196
|
+
self.keypoints = keypoints
|
|
197
|
+
self.normalized = normalized
|
|
198
|
+
|
|
199
|
+
if len(segments) > 0:
|
|
200
|
+
# list[np.array(1000, 2)] * num_samples
|
|
201
|
+
segments = resample_segments(segments)
|
|
202
|
+
# (N, 1000, 2)
|
|
203
|
+
segments = np.stack(segments, axis=0)
|
|
204
|
+
else:
|
|
205
|
+
segments = np.zeros((0, 1000, 2), dtype=np.float32)
|
|
206
|
+
self.segments = segments
|
|
207
|
+
|
|
208
|
+
def convert_bbox(self, format):
|
|
209
|
+
"""Convert bounding box format."""
|
|
210
|
+
self._bboxes.convert(format=format)
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def bbox_areas(self):
|
|
214
|
+
"""Calculate the area of bounding boxes."""
|
|
215
|
+
return self._bboxes.areas()
|
|
216
|
+
|
|
217
|
+
def scale(self, scale_w, scale_h, bbox_only=False):
|
|
218
|
+
"""this might be similar with denormalize func but without normalized sign."""
|
|
219
|
+
self._bboxes.mul(scale=(scale_w, scale_h, scale_w, scale_h))
|
|
220
|
+
if bbox_only:
|
|
221
|
+
return
|
|
222
|
+
self.segments[..., 0] *= scale_w
|
|
223
|
+
self.segments[..., 1] *= scale_h
|
|
224
|
+
if self.keypoints is not None:
|
|
225
|
+
self.keypoints[..., 0] *= scale_w
|
|
226
|
+
self.keypoints[..., 1] *= scale_h
|
|
227
|
+
|
|
228
|
+
def denormalize(self, w, h):
|
|
229
|
+
"""Denormalizes boxes, segments, and keypoints from normalized coordinates."""
|
|
230
|
+
if not self.normalized:
|
|
231
|
+
return
|
|
232
|
+
self._bboxes.mul(scale=(w, h, w, h))
|
|
233
|
+
self.segments[..., 0] *= w
|
|
234
|
+
self.segments[..., 1] *= h
|
|
235
|
+
if self.keypoints is not None:
|
|
236
|
+
self.keypoints[..., 0] *= w
|
|
237
|
+
self.keypoints[..., 1] *= h
|
|
238
|
+
self.normalized = False
|
|
239
|
+
|
|
240
|
+
def normalize(self, w, h):
|
|
241
|
+
"""Normalize bounding boxes, segments, and keypoints to image dimensions."""
|
|
242
|
+
if self.normalized:
|
|
243
|
+
return
|
|
244
|
+
self._bboxes.mul(scale=(1 / w, 1 / h, 1 / w, 1 / h))
|
|
245
|
+
self.segments[..., 0] /= w
|
|
246
|
+
self.segments[..., 1] /= h
|
|
247
|
+
if self.keypoints is not None:
|
|
248
|
+
self.keypoints[..., 0] /= w
|
|
249
|
+
self.keypoints[..., 1] /= h
|
|
250
|
+
self.normalized = True
|
|
251
|
+
|
|
252
|
+
def add_padding(self, padw, padh):
|
|
253
|
+
"""Handle rect and mosaic situation."""
|
|
254
|
+
assert not self.normalized, 'you should add padding with absolute coordinates.'
|
|
255
|
+
self._bboxes.add(offset=(padw, padh, padw, padh))
|
|
256
|
+
self.segments[..., 0] += padw
|
|
257
|
+
self.segments[..., 1] += padh
|
|
258
|
+
if self.keypoints is not None:
|
|
259
|
+
self.keypoints[..., 0] += padw
|
|
260
|
+
self.keypoints[..., 1] += padh
|
|
261
|
+
|
|
262
|
+
def __getitem__(self, index) -> 'Instances':
|
|
263
|
+
"""
|
|
264
|
+
Retrieve a specific instance or a set of instances using indexing.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
index (int, slice, or np.ndarray): The index, slice, or boolean array to select
|
|
268
|
+
the desired instances.
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Instances: A new Instances object containing the selected bounding boxes,
|
|
272
|
+
segments, and keypoints if present.
|
|
273
|
+
|
|
274
|
+
Note:
|
|
275
|
+
When using boolean indexing, make sure to provide a boolean array with the same
|
|
276
|
+
length as the number of instances.
|
|
277
|
+
"""
|
|
278
|
+
segments = self.segments[index] if len(self.segments) else self.segments
|
|
279
|
+
keypoints = self.keypoints[index] if self.keypoints is not None else None
|
|
280
|
+
bboxes = self.bboxes[index]
|
|
281
|
+
bbox_format = self._bboxes.format
|
|
282
|
+
return Instances(
|
|
283
|
+
bboxes=bboxes,
|
|
284
|
+
segments=segments,
|
|
285
|
+
keypoints=keypoints,
|
|
286
|
+
bbox_format=bbox_format,
|
|
287
|
+
normalized=self.normalized,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def flipud(self, h):
|
|
291
|
+
"""Flips the coordinates of bounding boxes, segments, and keypoints vertically."""
|
|
292
|
+
if self._bboxes.format == 'xyxy':
|
|
293
|
+
y1 = self.bboxes[:, 1].copy()
|
|
294
|
+
y2 = self.bboxes[:, 3].copy()
|
|
295
|
+
self.bboxes[:, 1] = h - y2
|
|
296
|
+
self.bboxes[:, 3] = h - y1
|
|
297
|
+
else:
|
|
298
|
+
self.bboxes[:, 1] = h - self.bboxes[:, 1]
|
|
299
|
+
self.segments[..., 1] = h - self.segments[..., 1]
|
|
300
|
+
if self.keypoints is not None:
|
|
301
|
+
self.keypoints[..., 1] = h - self.keypoints[..., 1]
|
|
302
|
+
|
|
303
|
+
def fliplr(self, w):
|
|
304
|
+
"""Reverses the order of the bounding boxes and segments horizontally."""
|
|
305
|
+
if self._bboxes.format == 'xyxy':
|
|
306
|
+
x1 = self.bboxes[:, 0].copy()
|
|
307
|
+
x2 = self.bboxes[:, 2].copy()
|
|
308
|
+
self.bboxes[:, 0] = w - x2
|
|
309
|
+
self.bboxes[:, 2] = w - x1
|
|
310
|
+
else:
|
|
311
|
+
self.bboxes[:, 0] = w - self.bboxes[:, 0]
|
|
312
|
+
self.segments[..., 0] = w - self.segments[..., 0]
|
|
313
|
+
if self.keypoints is not None:
|
|
314
|
+
self.keypoints[..., 0] = w - self.keypoints[..., 0]
|
|
315
|
+
|
|
316
|
+
def clip(self, w, h):
|
|
317
|
+
"""Clips bounding boxes, segments, and keypoints values to stay within image boundaries."""
|
|
318
|
+
ori_format = self._bboxes.format
|
|
319
|
+
self.convert_bbox(format='xyxy')
|
|
320
|
+
self.bboxes[:, [0, 2]] = self.bboxes[:, [0, 2]].clip(0, w)
|
|
321
|
+
self.bboxes[:, [1, 3]] = self.bboxes[:, [1, 3]].clip(0, h)
|
|
322
|
+
if ori_format != 'xyxy':
|
|
323
|
+
self.convert_bbox(format=ori_format)
|
|
324
|
+
self.segments[..., 0] = self.segments[..., 0].clip(0, w)
|
|
325
|
+
self.segments[..., 1] = self.segments[..., 1].clip(0, h)
|
|
326
|
+
if self.keypoints is not None:
|
|
327
|
+
self.keypoints[..., 0] = self.keypoints[..., 0].clip(0, w)
|
|
328
|
+
self.keypoints[..., 1] = self.keypoints[..., 1].clip(0, h)
|
|
329
|
+
|
|
330
|
+
def remove_zero_area_boxes(self):
|
|
331
|
+
"""Remove zero-area boxes, i.e. after clipping some boxes may have zero width or height. This removes them."""
|
|
332
|
+
good = self.bbox_areas > 0
|
|
333
|
+
if not all(good):
|
|
334
|
+
self._bboxes = self._bboxes[good]
|
|
335
|
+
if len(self.segments):
|
|
336
|
+
self.segments = self.segments[good]
|
|
337
|
+
if self.keypoints is not None:
|
|
338
|
+
self.keypoints = self.keypoints[good]
|
|
339
|
+
return good
|
|
340
|
+
|
|
341
|
+
def update(self, bboxes, segments=None, keypoints=None):
|
|
342
|
+
"""Updates instance variables."""
|
|
343
|
+
self._bboxes = Bboxes(bboxes, format=self._bboxes.format)
|
|
344
|
+
if segments is not None:
|
|
345
|
+
self.segments = segments
|
|
346
|
+
if keypoints is not None:
|
|
347
|
+
self.keypoints = keypoints
|
|
348
|
+
|
|
349
|
+
def __len__(self):
|
|
350
|
+
"""Return the length of the instance list."""
|
|
351
|
+
return len(self.bboxes)
|
|
352
|
+
|
|
353
|
+
@classmethod
|
|
354
|
+
def concatenate(cls, instances_list: List['Instances'], axis=0) -> 'Instances':
|
|
355
|
+
"""
|
|
356
|
+
Concatenates a list of Instances objects into a single Instances object.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
instances_list (List[Instances]): A list of Instances objects to concatenate.
|
|
360
|
+
axis (int, optional): The axis along which the arrays will be concatenated. Defaults to 0.
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Instances: A new Instances object containing the concatenated bounding boxes,
|
|
364
|
+
segments, and keypoints if present.
|
|
365
|
+
|
|
366
|
+
Note:
|
|
367
|
+
The `Instances` objects in the list should have the same properties, such as
|
|
368
|
+
the format of the bounding boxes, whether keypoints are present, and if the
|
|
369
|
+
coordinates are normalized.
|
|
370
|
+
"""
|
|
371
|
+
assert isinstance(instances_list, (list, tuple))
|
|
372
|
+
if not instances_list:
|
|
373
|
+
return cls(np.empty(0))
|
|
374
|
+
assert all(isinstance(instance, Instances) for instance in instances_list)
|
|
375
|
+
|
|
376
|
+
if len(instances_list) == 1:
|
|
377
|
+
return instances_list[0]
|
|
378
|
+
|
|
379
|
+
use_keypoint = instances_list[0].keypoints is not None
|
|
380
|
+
bbox_format = instances_list[0]._bboxes.format
|
|
381
|
+
normalized = instances_list[0].normalized
|
|
382
|
+
|
|
383
|
+
cat_boxes = np.concatenate([ins.bboxes for ins in instances_list], axis=axis)
|
|
384
|
+
cat_segments = np.concatenate([b.segments for b in instances_list], axis=axis)
|
|
385
|
+
cat_keypoints = np.concatenate([b.keypoints for b in instances_list], axis=axis) if use_keypoint else None
|
|
386
|
+
return cls(cat_boxes, cat_segments, cat_keypoints, bbox_format, normalized)
|
|
387
|
+
|
|
388
|
+
@property
|
|
389
|
+
def bboxes(self):
|
|
390
|
+
"""Return bounding boxes."""
|
|
391
|
+
return self._bboxes.bboxes
|