Passed
Pull Request — master (#270)
by Fernando
01:10
created

tests.utils   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 123
dl 0
loc 162
rs 10
c 0
b 0
f 0
wmc 20

12 Methods

Rating   Name   Duplication   Size   Complexity  
A TorchioTestCase.flip_affine_x() 0 5 2
A TorchioTestCase.make_4d() 0 5 2
A TorchioTestCase.make_2d() 0 5 2
A TorchioTestCase.get_reference_image_and_path() 0 5 1
A TorchioTestCase.get_inconsistent_sample() 0 22 1
A TorchioTestCase.setUp() 0 44 1
A TorchioTestCase.tearDown() 0 3 1
A TorchioTestCase.get_ixi_tiny() 0 3 1
A TorchioTestCase.get_sample_with_partial_volume_label_map() 0 9 1
A TorchioTestCase.assertTensorNotEqual() 0 2 1
B TorchioTestCase.get_image_path() 0 25 6
A TorchioTestCase.assertTensorEqual() 0 2 1
1
import copy
2
import shutil
3
import random
4
import tempfile
5
import unittest
6
from pathlib import Path
7
8
import torch
9
import numpy as np
10
import nibabel as nib
11
from numpy.testing import assert_array_equal, assert_raises
12
from torchio.datasets import IXITiny
13
from torchio import DATA, AFFINE, ScalarImage, LabelMap, SubjectsDataset, Subject
14
15
16
class TorchioTestCase(unittest.TestCase):
17
18
    def setUp(self):
19
        """Set up test fixtures, if any."""
20
        self.dir = Path(tempfile.gettempdir()) / '.torchio_tests'
21
        self.dir.mkdir(exist_ok=True)
22
        random.seed(42)
23
        np.random.seed(42)
24
25
        registration_matrix = np.array([
26
            [1, 0, 0, 10],
27
            [0, 1, 0, 0],
28
            [0, 0, 1.2, 0],
29
            [0, 0, 0, 1]
30
        ])
31
32
        subject_a = Subject(
33
            t1=ScalarImage(self.get_image_path('t1_a')),
34
        )
35
        subject_b = Subject(
36
            t1=ScalarImage(self.get_image_path('t1_b')),
37
            label=LabelMap(self.get_image_path('label_b', binary=True)),
38
        )
39
        subject_c = Subject(
40
            label=LabelMap(self.get_image_path('label_c', binary=True)),
41
        )
42
        subject_d = Subject(
43
            t1=ScalarImage(
44
                self.get_image_path('t1_d'),
45
                pre_affine=registration_matrix,
46
            ),
47
            t2=ScalarImage(self.get_image_path('t2_d')),
48
            label=LabelMap(self.get_image_path('label_d', binary=True)),
49
        )
50
        subject_a4 = Subject(
51
            t1=ScalarImage(self.get_image_path('t1_a'), components=2),
52
        )
53
        self.subjects_list = [
54
            subject_a,
55
            subject_a4,
56
            subject_b,
57
            subject_c,
58
            subject_d,
59
        ]
60
        self.dataset = SubjectsDataset(self.subjects_list)
61
        self.sample = self.dataset[-1]  # subject_d
62
63
    def make_2d(self, sample):
64
        sample = copy.deepcopy(sample)
65
        for image in sample.get_images(intensity_only=False):
66
            image[DATA] = image[DATA][..., :1]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable DATA does not seem to be defined.
Loading history...
67
        return sample
68
69
    def make_4d(self, sample):
70
        sample = copy.deepcopy(sample)
71
        for image in sample.get_images(intensity_only=False):
72
            image[DATA] = torch.cat(4 * (image[DATA],))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable DATA does not seem to be defined.
Loading history...
73
        return sample
74
75
    def flip_affine_x(self, sample):
76
        sample = copy.deepcopy(sample)
77
        for image in sample.get_images(intensity_only=False):
78
            image[AFFINE] = np.diag((-1, 1, 1, 1)) @ image[AFFINE]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable AFFINE does not seem to be defined.
Loading history...
79
        return sample
80
81
    def get_inconsistent_sample(self):
82
        """Return a sample containing images of different shape."""
83
        subject = Subject(
84
            t1=ScalarImage(self.get_image_path('t1_inc')),
85
            t2=ScalarImage(
86
                self.get_image_path('t2_inc', shape=(10, 20, 31))),
87
            label=LabelMap(
88
                self.get_image_path(
89
                    'label_inc',
90
                    shape=(8, 17, 25),
91
                    binary=True,
92
                ),
93
            ),
94
            label2=LabelMap(
95
                self.get_image_path(
96
                    'label2_inc',
97
                    shape=(18, 17, 25),
98
                    binary=True,
99
                ),
100
            ),
101
        )
102
        return subject
103
104
    def get_reference_image_and_path(self):
105
        """Return a reference image and its path"""
106
        path = self.get_image_path('ref', shape=(10, 20, 31), spacing=(1, 1, 2))
107
        image = ScalarImage(path)
108
        return image, path
109
110
    def get_sample_with_partial_volume_label_map(self, components=1):
111
        """Return a sample with a partial-volume label map."""
112
        return Subject(
113
            t1=ScalarImage(
114
                self.get_image_path('t1_d'),
115
            ),
116
            label=LabelMap(
117
                self.get_image_path(
118
                    'label_d2', binary=False, components=components
119
                )
120
            ),
121
        )
122
123
    def tearDown(self):
124
        """Tear down test fixtures, if any."""
125
        shutil.rmtree(self.dir)
126
127
    def get_ixi_tiny(self):
128
        root_dir = Path(tempfile.gettempdir()) / 'torchio' / 'ixi_tiny'
129
        return IXITiny(root_dir, download=True)
130
131
    def get_image_path(
132
            self,
133
            stem,
134
            binary=False,
135
            shape=(10, 20, 30),
136
            spacing=(1, 1, 1),
137
            components=1,
138
            add_nans=False,
139
            suffix=None,
140
            ):
141
        shape = (*shape, 1) if len(shape) == 2 else shape
142
        data = np.random.rand(components, *shape)
143
        if binary:
144
            data = (data > 0.5).astype(np.uint8)
145
        if add_nans:
146
            data[:] = np.nan
147
        affine = np.diag((*spacing, 1))
148
        if suffix is None:
149
            suffix = random.choice(('.nii.gz', '.nii', '.nrrd', '.img'))
150
        path = self.dir / f'{stem}{suffix}'
151
        if np.random.rand() > 0.5:
152
            path = str(path)
153
        image = ScalarImage(tensor=data, affine=affine, check_nans=not add_nans)
154
        image.save(path)
155
        return path
156
157
    def assertTensorNotEqual(self, *args, **kwargs):
158
        assert_raises(AssertionError, assert_array_equal, *args, **kwargs)
159
160
    def assertTensorEqual(self, *args, **kwargs):
161
        assert_array_equal(*args, **kwargs)
162