acvl-utils 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/PKG-INFO +7 -2
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/cropping_and_padding/bounding_boxes.py +115 -12
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils.egg-info/PKG-INFO +7 -2
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils.egg-info/SOURCES.txt +1 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/setup.py +1 -1
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_crop_and_pad.py +20 -7
- acvl_utils-0.2.3/tests/test_pad_bbox.py +46 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/__init__.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/array_manipulation/__init__.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/array_manipulation/resampling.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/array_manipulation/slicer.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/cropping_and_padding/__init__.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/cropping_and_padding/padding.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/instance_segmentation/__init__.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/instance_segmentation/instance_as_semantic_seg.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/instance_segmentation/instance_matching.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/miscellaneous/__init__.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/miscellaneous/ptqdm.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/miscellaneous/test_all_images_same.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/morphology/__init__.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/morphology/gpu_binary_morphology.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/morphology/morphology_helper.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/morphology/slice_interpolation.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils.egg-info/dependency_links.txt +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils.egg-info/requires.txt +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils.egg-info/top_level.txt +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/setup.cfg +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_component_removal.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_insert_crop.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_instance_matching.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_padding.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_ptqdm.py +0 -0
- {acvl_utils-0.2.2 → acvl_utils-0.2.3}/tests/test_slicer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: acvl_utils
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Super cool utilities that we just love to use
|
|
5
5
|
Author: Applied Computer Vision Lab, Helmholtz Imaging & Division of Medical Image Computing, German Cancer Research Center
|
|
6
6
|
Author-email: f.isensee@dkfz.de
|
|
@@ -12,3 +12,8 @@ Requires-Dist: SimpleITK
|
|
|
12
12
|
Requires-Dist: scikit-image
|
|
13
13
|
Requires-Dist: connected-components-3d
|
|
14
14
|
Requires-Dist: blosc2>=3.0.0b4
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: requires-dist
|
|
19
|
+
Dynamic: summary
|
|
@@ -11,7 +11,57 @@ import torch.nn.functional as F
|
|
|
11
11
|
def pad_bbox(bounding_box: Union[List[List[int]], Tuple[Tuple[int, int]]], pad_amount: Union[int, List[int]],
|
|
12
12
|
array_shape: Tuple[int, ...] = None) -> List[List[int]]:
|
|
13
13
|
"""
|
|
14
|
+
Pads a bounding box by a specified amount and optionally ensures that it stays within the bounds of an array.
|
|
14
15
|
|
|
16
|
+
Parameters:
|
|
17
|
+
-----------
|
|
18
|
+
bounding_box : Union[List[List[int]], Tuple[Tuple[int, int]]]
|
|
19
|
+
The input bounding box, represented as a list or tuple of coordinate pairs. Each pair corresponds to
|
|
20
|
+
one dimension and should have the form `[start, end]`, where `start` is inclusive and `end` is exclusive.
|
|
21
|
+
|
|
22
|
+
pad_amount : Union[int, List[int]]
|
|
23
|
+
The amount of padding to apply to each dimension of the bounding box.
|
|
24
|
+
- If an integer is provided, the same padding is applied to all dimensions.
|
|
25
|
+
- If a list is provided, each element specifies the padding for the corresponding dimension.
|
|
26
|
+
|
|
27
|
+
array_shape : Tuple[int, ...], optional
|
|
28
|
+
The shape of the array to which the bounding box is applied.
|
|
29
|
+
If provided, the padded bounding box will be clipped to stay within these bounds.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
--------
|
|
33
|
+
List[List[int]]
|
|
34
|
+
A new bounding box with the specified padding applied. Each dimension will be represented as a pair `[start, end]`.
|
|
35
|
+
|
|
36
|
+
Notes:
|
|
37
|
+
------
|
|
38
|
+
- The input `bounding_box` is converted to a list to ensure it can be modified without affecting the original data.
|
|
39
|
+
- The padding is applied symmetrically, reducing the `start` coordinate and increasing the `end` coordinate.
|
|
40
|
+
- If `array_shape` is provided, the padded bounding box will not exceed the valid indices of the array.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
---------
|
|
44
|
+
1. Padding a bounding box without array shape constraints:
|
|
45
|
+
```python
|
|
46
|
+
bbox = [[2, 10], [5, 15]]
|
|
47
|
+
padded_bbox = pad_bbox(bbox, pad_amount=2)
|
|
48
|
+
# Result: [[0, 12], [3, 17]]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
2. Padding with array shape constraints:
|
|
52
|
+
```python
|
|
53
|
+
bbox = [[2, 10], [5, 15]]
|
|
54
|
+
array_shape = (12, 20)
|
|
55
|
+
padded_bbox = pad_bbox(bbox, pad_amount=2, array_shape=array_shape)
|
|
56
|
+
# Result: [[0, 12], [3, 17]]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
3. Using dimension-specific padding:
|
|
60
|
+
```python
|
|
61
|
+
bbox = [[2, 10], [5, 15]]
|
|
62
|
+
padded_bbox = pad_bbox(bbox, pad_amount=[3, 1])
|
|
63
|
+
# Result: [[0, 13], [4, 16]]
|
|
64
|
+
```
|
|
15
65
|
"""
|
|
16
66
|
if isinstance(bounding_box, tuple):
|
|
17
67
|
# convert to list
|
|
@@ -41,10 +91,26 @@ def regionprops_bbox_to_proper_bbox(regionprops_bbox: Tuple[int, ...]) -> List[L
|
|
|
41
91
|
|
|
42
92
|
|
|
43
93
|
def bounding_box_to_slice(bounding_box: List[List[int]]):
|
|
94
|
+
"""
|
|
95
|
+
ALL bounding boxes in acvl_utils and nnU-Netv2 are half open interval [start, end)!
|
|
96
|
+
- Alignment with Python Slicing
|
|
97
|
+
- Ease of Subdivision
|
|
98
|
+
- Consistency in Multi-Dimensional Arrays
|
|
99
|
+
- Precedent in Computer Graphics
|
|
100
|
+
https://chatgpt.com/share/679203ec-3fbc-8013-a003-13a7adfb1e73
|
|
101
|
+
"""
|
|
44
102
|
return tuple([slice(*i) for i in bounding_box])
|
|
45
103
|
|
|
46
104
|
|
|
47
105
|
def crop_to_bbox(array: np.ndarray, bounding_box: List[List[int]]):
|
|
106
|
+
"""
|
|
107
|
+
ALL bounding boxes in acvl_utils and nnU-Netv2 are half open interval [start, end)!
|
|
108
|
+
- Alignment with Python Slicing
|
|
109
|
+
- Ease of Subdivision
|
|
110
|
+
- Consistency in Multi-Dimensional Arrays
|
|
111
|
+
- Precedent in Computer Graphics
|
|
112
|
+
https://chatgpt.com/share/679203ec-3fbc-8013-a003-13a7adfb1e73
|
|
113
|
+
"""
|
|
48
114
|
assert len(bounding_box) == len(array.shape), f"Dimensionality of bbox and array do not match. bbox has length " \
|
|
49
115
|
f"{len(bounding_box)} while array has dimension {len(array.shape)}"
|
|
50
116
|
slicer = bounding_box_to_slice(bounding_box)
|
|
@@ -53,10 +119,15 @@ def crop_to_bbox(array: np.ndarray, bounding_box: List[List[int]]):
|
|
|
53
119
|
|
|
54
120
|
def get_bbox_from_mask(mask: np.ndarray) -> List[List[int]]:
|
|
55
121
|
"""
|
|
122
|
+
ALL bounding boxes in acvl_utils and nnU-Netv2 are half open interval [start, end)!
|
|
123
|
+
- Alignment with Python Slicing
|
|
124
|
+
- Ease of Subdivision
|
|
125
|
+
- Consistency in Multi-Dimensional Arrays
|
|
126
|
+
- Precedent in Computer Graphics
|
|
127
|
+
https://chatgpt.com/share/679203ec-3fbc-8013-a003-13a7adfb1e73
|
|
128
|
+
|
|
56
129
|
this implementation uses less ram than the np.where one and is faster as well IF we expect the bounding box to
|
|
57
130
|
be close to the image size. If it's not it's likely slower!
|
|
58
|
-
|
|
59
|
-
bbox is returned so that you can just do slice(minzidx, maxzidx) to retrieve the object of interest with nothing cut off
|
|
60
131
|
|
|
61
132
|
:param mask:
|
|
62
133
|
:param outside_value:
|
|
@@ -97,6 +168,14 @@ def get_bbox_from_mask(mask: np.ndarray) -> List[List[int]]:
|
|
|
97
168
|
|
|
98
169
|
|
|
99
170
|
def get_bbox_from_mask_npwhere(mask: np.ndarray) -> List[List[int]]:
|
|
171
|
+
"""
|
|
172
|
+
ALL bounding boxes in acvl_utils and nnU-Netv2 are half open interval [start, end)!
|
|
173
|
+
- Alignment with Python Slicing
|
|
174
|
+
- Ease of Subdivision
|
|
175
|
+
- Consistency in Multi-Dimensional Arrays
|
|
176
|
+
- Precedent in Computer Graphics
|
|
177
|
+
https://chatgpt.com/share/679203ec-3fbc-8013-a003-13a7adfb1e73
|
|
178
|
+
"""
|
|
100
179
|
where = np.array(np.where(mask))
|
|
101
180
|
mins = np.min(where, 1)
|
|
102
181
|
maxs = np.max(where, 1) + 1
|
|
@@ -106,21 +185,34 @@ def get_bbox_from_mask_npwhere(mask: np.ndarray) -> List[List[int]]:
|
|
|
106
185
|
def crop_and_pad_nd(
|
|
107
186
|
image: Union[torch.Tensor, np.ndarray, blosc2.ndarray.NDArray],
|
|
108
187
|
bbox: List[List[int]],
|
|
109
|
-
pad_value
|
|
188
|
+
pad_value=0,
|
|
189
|
+
pad_mode: str = 'constant'
|
|
110
190
|
) -> Union[torch.Tensor, np.ndarray]:
|
|
111
191
|
"""
|
|
112
|
-
Crops a bounding box directly specified by bbox,
|
|
192
|
+
Crops a bounding box directly specified by bbox, adhering to the half-open interval [start, end).
|
|
113
193
|
If the bounding box extends beyond the image boundaries, the cropped area is padded
|
|
114
194
|
to maintain the desired size. Initial dimensions not included in bbox remain unaffected.
|
|
115
195
|
|
|
196
|
+
ALL bounding boxes in acvl_utils and nnU-Netv2 are half open interval [start, end)!
|
|
197
|
+
- Alignment with Python Slicing
|
|
198
|
+
- Ease of Subdivision
|
|
199
|
+
- Consistency in Multi-Dimensional Arrays
|
|
200
|
+
- Precedent in Computer Graphics
|
|
201
|
+
https://chatgpt.com/share/679203ec-3fbc-8013-a003-13a7adfb1e73
|
|
202
|
+
|
|
116
203
|
Parameters:
|
|
117
|
-
- image: N-dimensional torch.Tensor or
|
|
204
|
+
- image: N-dimensional torch.Tensor, np.ndarray, or blosc2.ndarray.NDArray representing the image.
|
|
118
205
|
- bbox: List of [[dim_min, dim_max], ...] defining the bounding box for the last dimensions.
|
|
206
|
+
Each dimension follows the half-open interval [start, end).
|
|
207
|
+
- pad_value: Value used for padding when bbox extends beyond image boundaries.
|
|
208
|
+
- pad_mode: Padding mode, one of 'constant', 'reflect', or 'replicate' (alias for 'edge').
|
|
119
209
|
|
|
120
210
|
Returns:
|
|
121
211
|
- Cropped and padded patch of the requested bounding box size, as the same type as `image`.
|
|
122
212
|
"""
|
|
123
213
|
|
|
214
|
+
assert pad_mode in ['constant', 'reflect', 'replicate', 'edge'], "Unsupported pad_mode."
|
|
215
|
+
|
|
124
216
|
# Determine the number of dimensions to crop based on bbox
|
|
125
217
|
crop_dims = len(bbox)
|
|
126
218
|
img_shape = image.shape
|
|
@@ -130,7 +222,7 @@ def crop_and_pad_nd(
|
|
|
130
222
|
slices = []
|
|
131
223
|
padding = []
|
|
132
224
|
output_shape = list(img_shape[:num_dims - crop_dims]) # Initial dimensions remain as in the original image
|
|
133
|
-
target_shape = output_shape + [max_val - min_val for min_val, max_val in bbox]
|
|
225
|
+
target_shape = output_shape + [max_val - min_val for min_val, max_val in bbox] # Half-open interval
|
|
134
226
|
|
|
135
227
|
# Iterate through dimensions, applying bbox to the last `crop_dims` dimensions
|
|
136
228
|
for i in range(num_dims):
|
|
@@ -138,13 +230,13 @@ def crop_and_pad_nd(
|
|
|
138
230
|
# For initial dimensions not covered by bbox, include the entire dimension
|
|
139
231
|
slices.append(slice(None))
|
|
140
232
|
padding.append([0, 0])
|
|
141
|
-
output_shape.append(img_shape[i])
|
|
233
|
+
output_shape.append(img_shape[i])
|
|
142
234
|
else:
|
|
143
235
|
# For dimensions specified in bbox, directly use the min and max bounds
|
|
144
236
|
dim_idx = i - (num_dims - crop_dims) # Index within bbox
|
|
145
237
|
|
|
146
238
|
min_val = bbox[dim_idx][0]
|
|
147
|
-
max_val = bbox[dim_idx][1]
|
|
239
|
+
max_val = bbox[dim_idx][1] # This is exclusive by definition
|
|
148
240
|
|
|
149
241
|
# Check if the bounding box is completely outside the image bounds
|
|
150
242
|
if max_val <= 0 or min_val >= img_shape[i]:
|
|
@@ -154,9 +246,9 @@ def crop_and_pad_nd(
|
|
|
154
246
|
elif isinstance(image, (np.ndarray, blosc2.ndarray.NDArray)):
|
|
155
247
|
return np.zeros(target_shape, dtype=image.dtype)
|
|
156
248
|
|
|
157
|
-
# Calculate valid cropping ranges within image bounds
|
|
249
|
+
# Calculate valid cropping ranges within image bounds (half-open interval)
|
|
158
250
|
valid_min = max(min_val, 0)
|
|
159
|
-
valid_max = min(max_val, img_shape[i]) #
|
|
251
|
+
valid_max = min(max_val, img_shape[i]) # Exclusive upper bound
|
|
160
252
|
slices.append(slice(valid_min, valid_max))
|
|
161
253
|
|
|
162
254
|
# Calculate padding needed for this dimension
|
|
@@ -172,11 +264,22 @@ def crop_and_pad_nd(
|
|
|
172
264
|
|
|
173
265
|
# Apply padding to the cropped patch
|
|
174
266
|
if isinstance(image, torch.Tensor):
|
|
267
|
+
if pad_mode == 'edge':
|
|
268
|
+
pad_mode = 'replicate'
|
|
269
|
+
cropped = cropped[None, None] # Adjust shape for PyTorch padding requirements
|
|
175
270
|
flattened_padding = [p for sublist in reversed(padding) for p in sublist] # Flatten in reverse order for PyTorch
|
|
176
|
-
padded_cropped = F.pad(cropped, flattened_padding, mode=
|
|
271
|
+
padded_cropped = F.pad(cropped, flattened_padding, mode=pad_mode, value=pad_value)
|
|
272
|
+
if pad_mode == 'replicate':
|
|
273
|
+
padded_cropped = padded_cropped[0, 0]
|
|
177
274
|
elif isinstance(image, (np.ndarray, blosc2.ndarray.NDArray)):
|
|
275
|
+
if pad_mode == 'replicate':
|
|
276
|
+
pad_mode = 'edge'
|
|
277
|
+
if pad_mode == 'edge':
|
|
278
|
+
kwargs = {}
|
|
279
|
+
else:
|
|
280
|
+
kwargs = {'constant_values': pad_value}
|
|
178
281
|
pad_width = [(p[0], p[1]) for p in padding]
|
|
179
|
-
padded_cropped = np.pad(cropped, pad_width=pad_width, mode=
|
|
282
|
+
padded_cropped = np.pad(cropped, pad_width=pad_width, mode=pad_mode, **kwargs)
|
|
180
283
|
else:
|
|
181
284
|
raise ValueError(f'Unsupported image type {type(image)}')
|
|
182
285
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: acvl_utils
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Super cool utilities that we just love to use
|
|
5
5
|
Author: Applied Computer Vision Lab, Helmholtz Imaging & Division of Medical Image Computing, German Cancer Research Center
|
|
6
6
|
Author-email: f.isensee@dkfz.de
|
|
@@ -12,3 +12,8 @@ Requires-Dist: SimpleITK
|
|
|
12
12
|
Requires-Dist: scikit-image
|
|
13
13
|
Requires-Dist: connected-components-3d
|
|
14
14
|
Requires-Dist: blosc2>=3.0.0b4
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: requires-dist
|
|
19
|
+
Dynamic: summary
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_namespace_packages
|
|
|
2
2
|
|
|
3
3
|
setup(name='acvl_utils',
|
|
4
4
|
packages=find_namespace_packages(include=["acvl_utils", "acvl_utils.*"]),
|
|
5
|
-
version='0.2.
|
|
5
|
+
version='0.2.3',
|
|
6
6
|
description='Super cool utilities that we just love to use',
|
|
7
7
|
# url='',
|
|
8
8
|
author='Applied Computer Vision Lab, Helmholtz Imaging & Division of Medical Image Computing, German Cancer Research Center',
|
|
@@ -264,7 +264,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
264
264
|
self.assertEqual(cropped_patch.shape, (5, 10, 10, 5))
|
|
265
265
|
np.testing.assert_array_equal(cropped_patch, self.image_np[:, :, :, 3:8])
|
|
266
266
|
|
|
267
|
-
|
|
268
267
|
def test_two_dimensions_crop_np(self):
|
|
269
268
|
"""Test cropping the last two dimensions of a 4D np.ndarray."""
|
|
270
269
|
bbox = [[3, 8], [1, 7]]
|
|
@@ -274,7 +273,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
274
273
|
self.assertEqual(cropped_patch.shape, (5, 10, 5, 6))
|
|
275
274
|
np.testing.assert_array_equal(cropped_patch, self.image_np[:, :, 3:8, 1:7])
|
|
276
275
|
|
|
277
|
-
|
|
278
276
|
def test_three_dimensions_crop_np(self):
|
|
279
277
|
"""Test cropping the last three dimensions of a 4D np.ndarray."""
|
|
280
278
|
bbox = [[1, 6], [2, 9], [3, 8]]
|
|
@@ -284,7 +282,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
284
282
|
self.assertEqual(cropped_patch.shape, (5, 5, 7, 5))
|
|
285
283
|
np.testing.assert_array_equal(cropped_patch, self.image_np[:, 1:6, 2:9, 3:8])
|
|
286
284
|
|
|
287
|
-
|
|
288
285
|
def test_all_dimensions_crop_np(self):
|
|
289
286
|
"""Test cropping all dimensions of a 4D np.ndarray."""
|
|
290
287
|
bbox = [[1, 4], [2, 7], [0, 6], [4, 9]]
|
|
@@ -294,7 +291,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
294
291
|
self.assertEqual(cropped_patch.shape, (3, 5, 6, 5))
|
|
295
292
|
np.testing.assert_array_equal(cropped_patch, self.image_np[1:4, 2:7, 0:6, 4:9])
|
|
296
293
|
|
|
297
|
-
|
|
298
294
|
def test_single_dimension_crop_torch(self):
|
|
299
295
|
"""Test cropping only the last dimension of a 4D torch.Tensor."""
|
|
300
296
|
bbox = [[3, 8]]
|
|
@@ -304,7 +300,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
304
300
|
self.assertEqual(cropped_patch.shape, (5, 10, 10, 5))
|
|
305
301
|
torch.testing.assert_close(cropped_patch, self.image_torch[:, :, :, 3:8])
|
|
306
302
|
|
|
307
|
-
|
|
308
303
|
def test_two_dimensions_crop_torch(self):
|
|
309
304
|
"""Test cropping the last two dimensions of a 4D torch.Tensor."""
|
|
310
305
|
bbox = [[3, 8], [1, 7]]
|
|
@@ -314,7 +309,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
314
309
|
self.assertEqual(cropped_patch.shape, (5, 10, 5, 6))
|
|
315
310
|
torch.testing.assert_close(cropped_patch, self.image_torch[:, :, 3:8, 1:7])
|
|
316
311
|
|
|
317
|
-
|
|
318
312
|
def test_three_dimensions_crop_torch(self):
|
|
319
313
|
"""Test cropping the last three dimensions of a 4D torch.Tensor."""
|
|
320
314
|
bbox = [[1, 6], [2, 9], [3, 8]]
|
|
@@ -324,7 +318,6 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
324
318
|
self.assertEqual(cropped_patch.shape, (5, 5, 7, 5))
|
|
325
319
|
torch.testing.assert_close(cropped_patch, self.image_torch[:, 1:6, 2:9, 3:8])
|
|
326
320
|
|
|
327
|
-
|
|
328
321
|
def test_all_dimensions_crop_torch(self):
|
|
329
322
|
"""Test cropping all dimensions of a 4D torch.Tensor."""
|
|
330
323
|
bbox = [[1, 4], [2, 7], [0, 6], [4, 9]]
|
|
@@ -334,6 +327,26 @@ class TestCropAndPadND(unittest.TestCase):
|
|
|
334
327
|
self.assertEqual(cropped_patch.shape, (3, 5, 6, 5))
|
|
335
328
|
torch.testing.assert_close(cropped_patch, self.image_torch[1:4, 2:7, 0:6, 4:9])
|
|
336
329
|
|
|
330
|
+
def test_pad_all_dims(self):
|
|
331
|
+
seg = np.ones((128, 128))
|
|
332
|
+
bbox = [[-5, 133], [-5, 133]]
|
|
333
|
+
out = crop_and_pad_nd(seg, bbox)
|
|
334
|
+
self.assertEqual(out.shape, (138, 138))
|
|
335
|
+
bbox_reverse = [[5, 133], [5, 133]]
|
|
336
|
+
out2 = crop_and_pad_nd(out, bbox_reverse)
|
|
337
|
+
self.assertEqual(out2.shape, (128, 128))
|
|
338
|
+
self.assertTrue(np.all(out2==1))
|
|
339
|
+
|
|
340
|
+
def test_pad_all_dims_torch(self):
|
|
341
|
+
seg = torch.ones((128, 128))
|
|
342
|
+
bbox = [[-5, 133], [-5, 133]]
|
|
343
|
+
out = crop_and_pad_nd(seg, bbox)
|
|
344
|
+
self.assertEqual(out.shape, (138, 138))
|
|
345
|
+
bbox_reverse = [[5, 133], [5, 133]]
|
|
346
|
+
out2 = crop_and_pad_nd(out, bbox_reverse)
|
|
347
|
+
self.assertEqual(out2.shape, (128, 128))
|
|
348
|
+
self.assertTrue(torch.all(out2==1))
|
|
349
|
+
|
|
337
350
|
|
|
338
351
|
if __name__ == "__main__":
|
|
339
352
|
unittest.main()
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from acvl_utils.cropping_and_padding.bounding_boxes import pad_bbox
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestPadBBox(unittest.TestCase):
|
|
7
|
+
|
|
8
|
+
def test_no_array_shape(self):
|
|
9
|
+
bbox = [[2, 10], [5, 15]]
|
|
10
|
+
pad_amount = 2
|
|
11
|
+
expected = [[0, 12], [3, 17]]
|
|
12
|
+
result = pad_bbox(bbox, pad_amount)
|
|
13
|
+
self.assertEqual(result, expected)
|
|
14
|
+
|
|
15
|
+
def test_with_array_shape(self):
|
|
16
|
+
bbox = [[2, 10], [5, 15]]
|
|
17
|
+
pad_amount = 2
|
|
18
|
+
array_shape = (12, 20)
|
|
19
|
+
expected = [[0, 12], [3, 17]]
|
|
20
|
+
result = pad_bbox(bbox, pad_amount, array_shape)
|
|
21
|
+
self.assertEqual(result, expected)
|
|
22
|
+
|
|
23
|
+
def test_dimension_specific_padding(self):
|
|
24
|
+
bbox = [[2, 10], [5, 15]]
|
|
25
|
+
pad_amount = [3, 1]
|
|
26
|
+
expected = [[0, 13], [4, 16]]
|
|
27
|
+
result = pad_bbox(bbox, pad_amount)
|
|
28
|
+
self.assertEqual(result, expected)
|
|
29
|
+
|
|
30
|
+
def test_clipping_with_array_shape(self):
|
|
31
|
+
bbox = [[2, 10], [5, 15]]
|
|
32
|
+
pad_amount = 5
|
|
33
|
+
array_shape = (12, 18)
|
|
34
|
+
expected = [[0, 12], [0, 18]]
|
|
35
|
+
result = pad_bbox(bbox, pad_amount, array_shape)
|
|
36
|
+
self.assertEqual(result, expected)
|
|
37
|
+
|
|
38
|
+
def test_no_padding(self):
|
|
39
|
+
bbox = [[2, 10], [5, 15]]
|
|
40
|
+
pad_amount = 0
|
|
41
|
+
expected = [[2, 10], [5, 15]]
|
|
42
|
+
result = pad_bbox(bbox, pad_amount)
|
|
43
|
+
self.assertEqual(result, expected)
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{acvl_utils-0.2.2 → acvl_utils-0.2.3}/acvl_utils/instance_segmentation/instance_as_semantic_seg.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|