tests.transforms.preprocessing.test_crop_pad   B
last analyzed

Complexity

Total Complexity 49

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 202
dl 0
loc 243
rs 8.48
c 0
b 0
f 0
wmc 49

25 Methods

Rating   Name   Duplication   Size   Complexity  
A TestCropOrPad.test_2d() 0 12 1
A TestCropOrPad.test_no_changes_mask() 0 12 3
A TestCropOrPad.test_no_target_no_mask() 0 3 2
A TestCropOrPad.test_no_changes() 0 7 1
A TestCropOrPad.test_mask_only_crop() 0 2 1
A TestCropOrPad.test_only_crop_pad_true() 0 3 2
A TestCropOrPad.test_shape_right() 0 7 2
A TestCropOrPad.test_shape_one() 0 6 2
A TestCropOrPad.test_mask_only_pad() 0 2 1
A TestCropOrPad.test_different_shape() 0 8 2
A TestCropOrPad.test_only_pad() 0 7 2
A TestCropOrPad.test_shape_negative() 0 3 2
A TestCropOrPad.test_shape_float() 0 3 2
A TestCropOrPad.test_persistent_bounds_params() 0 19 2
A TestCropOrPad.mask_only() 0 16 3
A TestCropOrPad.test_wrong_mask_name() 0 4 2
A TestCropOrPad.test_only_crop_true() 0 11 3
A TestCropOrPad.test_only_crop() 0 7 2
A TestCropOrPad.test_no_target() 0 3 1
A TestCropOrPad.test_shape_string() 0 3 2
A TestCropOrPad.test_mask_corners() 0 25 2
A TestCropOrPad.test_only_pad_true() 0 11 3
A TestCropOrPad.test_labels_but_no_mask() 0 3 2
A TestCropOrPad.test_empty_mask() 0 7 2
A TestCropOrPad.test_center_mask() 0 21 2

How to fix   Complexity   

Complexity

Complex classes like tests.transforms.preprocessing.test_crop_pad often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import numpy as np
2
import pytest
3
4
import torchio as tio
5
6
from ...utils import TorchioTestCase
7
8
9
class TestCropOrPad(TorchioTestCase):
10
    """Tests for `CropOrPad`."""
11
12
    def test_no_changes(self):
13
        sample_t1 = self.sample_subject['t1']
14
        shape = sample_t1.spatial_shape
15
        transform = tio.CropOrPad(shape)
16
        transformed = transform(self.sample_subject)
17
        self.assert_tensor_equal(sample_t1.data, transformed['t1'].data)
18
        self.assert_tensor_equal(sample_t1.affine, transformed['t1'].affine)
19
20
    def test_no_changes_mask(self):
21
        sample_t1 = self.sample_subject['t1']
22
        sample_mask = self.sample_subject['label'].data
23
        sample_mask *= 0
24
        shape = sample_t1.spatial_shape
25
        transform = tio.CropOrPad(shape, mask_name='label')
26
        with pytest.warns(RuntimeWarning):
27
            transformed = transform(self.sample_subject)
28
        for key in transformed:
29
            image = self.sample_subject[key]
30
            self.assert_tensor_equal(image.data, transformed[key].data)
31
            self.assert_tensor_equal(image.affine, transformed[key].affine)
32
33
    def test_different_shape(self):
34
        shape = self.sample_subject['t1'].spatial_shape
35
        target_shape = 9, 21, 30
36
        transform = tio.CropOrPad(target_shape)
37
        transformed = transform(self.sample_subject)
38
        for key in transformed:
39
            result_shape = transformed[key].spatial_shape
40
            self.assertNotEqual(shape, result_shape)
41
42
    def test_shape_right(self):
43
        target_shape = 9, 21, 30
44
        transform = tio.CropOrPad(target_shape)
45
        transformed = transform(self.sample_subject)
46
        for key in transformed:
47
            result_shape = transformed[key].spatial_shape
48
            assert target_shape == result_shape
49
50
    def test_only_pad(self):
51
        target_shape = 11, 22, 30
52
        transform = tio.CropOrPad(target_shape)
53
        transformed = transform(self.sample_subject)
54
        for key in transformed:
55
            result_shape = transformed[key].spatial_shape
56
            assert target_shape == result_shape
57
58
    def test_only_crop(self):
59
        target_shape = 9, 18, 30
60
        transform = tio.CropOrPad(target_shape)
61
        transformed = transform(self.sample_subject)
62
        for key in transformed:
63
            result_shape = transformed[key].spatial_shape
64
            assert target_shape == result_shape
65
66
    def test_shape_negative(self):
67
        with pytest.raises(ValueError):
68
            tio.CropOrPad(-1)
69
70
    def test_shape_float(self):
71
        with pytest.raises(ValueError):
72
            tio.CropOrPad(2.5)
73
74
    def test_shape_string(self):
75
        with pytest.raises(ValueError):
76
            tio.CropOrPad('')
77
78
    def test_shape_one(self):
79
        transform = tio.CropOrPad(1)
80
        transformed = transform(self.sample_subject)
81
        for key in transformed:
82
            result_shape = transformed[key].spatial_shape
83
            assert result_shape == (1, 1, 1)
84
85
    def test_wrong_mask_name(self):
86
        cop = tio.CropOrPad(1, mask_name='wrong')
87
        with pytest.warns(RuntimeWarning):
88
            cop(self.sample_subject)
89
90
    def test_empty_mask(self):
91
        target_shape = 8, 22, 30
92
        transform = tio.CropOrPad(target_shape, mask_name='label')
93
        mask = self.sample_subject['label'].data
94
        mask *= 0
95
        with pytest.warns(RuntimeWarning):
96
            transform(self.sample_subject)
97
98
    def mask_only(self, target_shape):
99
        transform = tio.CropOrPad(target_shape, mask_name='label')
100
        mask = self.sample_subject['label'].data
101
        mask *= 0
102
        mask[0, 4:6, 5:8, 3:7] = 1
103
        transformed = transform(self.sample_subject)
104
        shapes = []
105
        for key in transformed:
106
            result_shape = transformed[key].spatial_shape
107
            shapes.append(result_shape)
108
        set_shapes = set(shapes)
109
        message = f'Images have different shapes: {set_shapes}'
110
        assert len(set_shapes) == 1, message
111
        for key in transformed:
112
            result_shape = transformed[key].spatial_shape
113
            assert target_shape == result_shape, f'Wrong shape for image: {key}'
114
115
    def test_mask_only_pad(self):
116
        self.mask_only((11, 22, 30))
117
118
    def test_mask_only_crop(self):
119
        self.mask_only((9, 18, 30))
120
121
    def test_center_mask(self):
122
        """The mask bounding box and the input image have the same center."""
123
        target_shape = 8, 22, 30
124
        transform_center = tio.CropOrPad(target_shape)
125
        transform_mask = tio.CropOrPad(target_shape, mask_name='label')
126
        mask = self.sample_subject['label'].data
127
        mask *= 0
128
        mask[0, 4:6, 9:11, 14:16] = 1
129
        transformed_center = transform_center(self.sample_subject)
130
        transformed_mask = transform_mask(self.sample_subject)
131
        zipped = zip(transformed_center.values(), transformed_mask.values())
132
        for image_center, image_mask in zipped:
133
            self.assert_tensor_equal(
134
                image_center.data,
135
                image_mask.data,
136
                msg='Data is different after cropping',
137
            )
138
            self.assert_tensor_equal(
139
                image_center.affine,
140
                image_mask.affine,
141
                msg='Physical position is different after cropping',
142
            )
143
144
    def test_mask_corners(self):
145
        """The mask bounding box and the input image have the same center."""
146
        target_shape = 8, 22, 30
147
        transform_center = tio.CropOrPad(target_shape)
148
        transform_mask = tio.CropOrPad(
149
            target_shape,
150
            mask_name='label',
151
        )
152
        mask = self.sample_subject['label'].data
153
        mask *= 0
154
        mask[0, 0, 0, 0] = 1
155
        mask[0, -1, -1, -1] = 1
156
        transformed_center = transform_center(self.sample_subject)
157
        transformed_mask = transform_mask(self.sample_subject)
158
        zipped = zip(transformed_center.values(), transformed_mask.values())
159
        for image_center, image_mask in zipped:
160
            self.assert_tensor_equal(
161
                image_center.data,
162
                image_mask.data,
163
                msg='Data is different after cropping',
164
            )
165
            self.assert_tensor_equal(
166
                image_center.affine,
167
                image_mask.affine,
168
                msg='Physical position is different after cropping',
169
            )
170
171
    def test_2d(self):
172
        # https://github.com/TorchIO-project/torchio/issues/434
173
        image = np.random.rand(1, 16, 16, 1)
174
        mask = np.zeros_like(image, dtype=bool)
175
        mask[0, 7, 0] = True
176
        subject = tio.Subject(
177
            image=tio.ScalarImage(tensor=image),
178
            mask=tio.LabelMap(tensor=mask),
179
        )
180
        transform = tio.CropOrPad((12, 12, 1), mask_name='mask')
181
        transformed = transform(subject)
182
        assert transformed.shape == (1, 12, 12, 1)
183
184
    def test_no_target_no_mask(self):
185
        with pytest.raises(ValueError):
186
            tio.CropOrPad()
187
188
    def test_labels_but_no_mask(self):
189
        with pytest.raises(ValueError):
190
            tio.CropOrPad(target_shape=(3, 4, 5), labels=[2, 3])
191
192
    def test_no_target(self):
193
        crop_with_mask = tio.CropOrPad(mask_name='label')
194
        crop_with_mask(self.sample_subject)
195
196
    def test_persistent_bounds_params(self):
197
        # https://github.com/TorchIO-project/torchio/issues/757
198
        shape = (1, 5, 5, 5)
199
        mask_a = np.zeros(shape)
200
        mask_a[0, 2, 2, 2] = 1
201
        mask_b = mask_a.copy()
202
        mask_b[0, 1:4, 1:4, 1:4] = 1
203
        tensor = np.ones(shape)
204
        image_a = tio.ScalarImage(tensor=tensor)
205
        mask_a = tio.LabelMap(tensor=mask_a)
206
        subject_a = tio.Subject(image=image_a, mask=mask_a)
207
        image_b = tio.ScalarImage(tensor=tensor)
208
        mask_b = tio.LabelMap(tensor=mask_b)
209
        subject_b = tio.Subject(image=image_b, mask=mask_b)
210
        crop = tio.CropOrPad(mask_name='mask')
211
        for _ in range(2):
212
            shape_a = crop(subject_a).image.shape
213
            shape_b = crop(subject_b).image.shape
214
            assert shape_a != shape_b
215
216
    def test_only_crop_pad_true(self):
217
        with pytest.raises(ValueError):
218
            tio.CropOrPad((1, 2, 3), only_crop=True, only_pad=True)
219
220
    def test_only_pad_true(self):
221
        target_shape = 9, 21, 30
222
        orig_shape = self.sample_subject['t1'].spatial_shape
223
        expected_shape = tuple(
224
            t if t > o else o for o, t in zip(orig_shape, target_shape)
225
        )
226
        transform = tio.CropOrPad(target_shape, only_pad=True)
227
        transformed = transform(self.sample_subject)
228
        for key in transformed:
229
            result_shape = transformed[key].spatial_shape
230
            assert result_shape == expected_shape
231
232
    def test_only_crop_true(self):
233
        target_shape = 9, 21, 30
234
        orig_shape = self.sample_subject['t1'].spatial_shape
235
        expected_shape = tuple(
236
            t if t < o else o for o, t in zip(orig_shape, target_shape)
237
        )
238
        transform = tio.CropOrPad(target_shape, only_crop=True)
239
        transformed = transform(self.sample_subject)
240
        for key in transformed:
241
            result_shape = transformed[key].spatial_shape
242
            assert result_shape == expected_shape
243