mrid-python 0.1.3__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.
- mrid/__init__.py +5 -0
- mrid/atlas/MNI152/__init__.py +80 -0
- mrid/atlas/SRI24/__init__.py +77 -0
- mrid/atlas/__init__.py +7 -0
- mrid/loading/__init__.py +1 -0
- mrid/loading/convert.py +68 -0
- mrid/preprocessing/__init__.py +12 -0
- mrid/preprocessing/bias_field_correction.py +28 -0
- mrid/preprocessing/cropping.py +36 -0
- mrid/preprocessing/registration.py +251 -0
- mrid/preprocessing/skullstripping.py +185 -0
- mrid/study.py +442 -0
- mrid/utils/__init__.py +3 -0
- mrid/utils/dcm2niix.py +90 -0
- mrid/utils/dicom_uid_fixer.py +86 -0
- mrid/utils/plotting.py +102 -0
- mrid/utils/python_utils.py +48 -0
- mrid/utils/stl_utils.py +70 -0
- mrid/utils/torch_utils.py +16 -0
- mrid_python-0.1.3.dist-info/METADATA +140 -0
- mrid_python-0.1.3.dist-info/RECORD +27 -0
- mrid_python-0.1.3.dist-info/WHEEL +5 -0
- mrid_python-0.1.3.dist-info/top_level.txt +2 -0
- tests/test_loading.py +82 -0
- tests/test_preprocessing.py +43 -0
- tests/test_study.py +136 -0
- tests/test_utils.py +16 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""sanity tests"""
|
|
2
|
+
import numpy as np
|
|
3
|
+
import SimpleITK as sitk
|
|
4
|
+
|
|
5
|
+
from mrid.preprocessing import bias_field_correction
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_resize():
|
|
9
|
+
from mrid import Study
|
|
10
|
+
study = Study(t1=np.random.rand(10, 20, 30).astype(np.float32))
|
|
11
|
+
resized = study.resize([5, 10, 15])
|
|
12
|
+
assert 't1' in resized
|
|
13
|
+
assert study.numpy("t1").shape == (10, 20, 30)
|
|
14
|
+
assert resized.numpy("t1").shape == (5, 10, 15)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_downsample():
|
|
18
|
+
from mrid import Study
|
|
19
|
+
study = Study(t1=np.random.rand(10, 20, 30).astype(np.float32))
|
|
20
|
+
downsampled = study.downsample(factor=2.0) # 2x downsampling
|
|
21
|
+
assert 't1' in downsampled
|
|
22
|
+
assert study.numpy("t1").shape == (10, 20, 30)
|
|
23
|
+
assert downsampled.numpy("t1").shape == (5, 10, 15)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_bias_field_correction():
|
|
27
|
+
img = sitk.Image(10, 10, 10, sitk.sitkFloat32)
|
|
28
|
+
corrected = bias_field_correction.n4_bias_field_correction(img, shrink=4)
|
|
29
|
+
assert isinstance(corrected, sitk.Image)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_crop_bg():
|
|
33
|
+
from mrid import Study
|
|
34
|
+
data = {
|
|
35
|
+
't1': np.random.rand(20, 20, 20).astype(np.float32),
|
|
36
|
+
't2': np.random.rand(20, 20, 20).astype(np.float32)
|
|
37
|
+
}
|
|
38
|
+
study = Study(data)
|
|
39
|
+
cropped = study.crop_bg('t1')
|
|
40
|
+
assert 't1' in cropped
|
|
41
|
+
assert 't2' in cropped
|
|
42
|
+
|
|
43
|
+
assert study.numpy("t1").shape == study.numpy("t2").shape
|
tests/test_study.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
import SimpleITK as sitk
|
|
6
|
+
|
|
7
|
+
from mrid import Study
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_study_init():
|
|
11
|
+
# numpy
|
|
12
|
+
study1 = Study(
|
|
13
|
+
t1=np.random.rand(10, 20, 30).astype(np.float32),
|
|
14
|
+
t2=np.random.rand(10, 20, 30).astype(np.float32)
|
|
15
|
+
)
|
|
16
|
+
assert len(study1) == 2
|
|
17
|
+
|
|
18
|
+
# sitk
|
|
19
|
+
sitk_img1 = sitk.Image(10, 20, 30, sitk.sitkFloat32)
|
|
20
|
+
sitk_img2 = sitk.Image(15, 25, 35, sitk.sitkFloat32)
|
|
21
|
+
study2 = Study(t1=sitk_img1, t2=sitk_img2)
|
|
22
|
+
assert len(study2) == 2
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_study_get():
|
|
26
|
+
study = Study(
|
|
27
|
+
t1=np.random.rand(10, 20, 30),
|
|
28
|
+
t2=np.random.rand(10, 20, 30),
|
|
29
|
+
seg_brain=np.random.randint(0, 2, (10, 20, 30)),
|
|
30
|
+
info_patient={'age': 25, 'gender': 'M'}
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
assert 't1' in study
|
|
34
|
+
assert 't2' in study
|
|
35
|
+
assert 'seg_brain' in study
|
|
36
|
+
assert 'info_patient' in study
|
|
37
|
+
|
|
38
|
+
# test get_images
|
|
39
|
+
images = study.get_images()
|
|
40
|
+
assert tuple(images.keys()) == ("t1", "t2", "seg_brain")
|
|
41
|
+
|
|
42
|
+
# test get_scans method (excludes segmentations and info)
|
|
43
|
+
scans = study.get_scans()
|
|
44
|
+
assert tuple(scans.keys()) == ("t1", "t2",)
|
|
45
|
+
|
|
46
|
+
# test get_segmentations
|
|
47
|
+
segmentations = study.get_segmentations()
|
|
48
|
+
assert tuple(segmentations.keys()) == ("seg_brain", )
|
|
49
|
+
|
|
50
|
+
#test get_info
|
|
51
|
+
info = study.get_info()
|
|
52
|
+
assert tuple(info.keys()) == ("info_patient", )
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_apply():
|
|
56
|
+
study = Study(t1=np.random.rand(10, 20, 30))
|
|
57
|
+
result = study.apply(lambda x: x, lambda x: x)
|
|
58
|
+
assert 't1' in result
|
|
59
|
+
|
|
60
|
+
result2 = study.apply(None, None)
|
|
61
|
+
assert 't1' in result2
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pytest.mark.parametrize("dtype", [np.float32, np.float64])
|
|
65
|
+
def test_cast(dtype):
|
|
66
|
+
data = np.random.rand(5, 10, 15).astype(np.float32)
|
|
67
|
+
study = Study(t1=data)
|
|
68
|
+
|
|
69
|
+
if dtype == np.float32:
|
|
70
|
+
casted = study.cast_float32()
|
|
71
|
+
else:
|
|
72
|
+
casted = study.cast_float64()
|
|
73
|
+
|
|
74
|
+
assert 't1' in casted
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_normalize():
|
|
78
|
+
study = Study(t1=np.random.rand(10, 20, 30).astype(np.float32))
|
|
79
|
+
normalized = study.normalize()
|
|
80
|
+
assert 't1' in normalized
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_rescale_intensity():
|
|
84
|
+
study = Study(t1=np.random.rand(10, 20, 30).astype(np.float32))
|
|
85
|
+
rescaled = study.rescale_intensity(0.0, 1.0)
|
|
86
|
+
assert 't1' in rescaled
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_numpy_method():
|
|
90
|
+
data = np.random.rand(10, 20, 30).astype(np.float32)
|
|
91
|
+
study = Study(t1=data)
|
|
92
|
+
|
|
93
|
+
numpy_array = study.numpy('t1')
|
|
94
|
+
assert isinstance(numpy_array, np.ndarray)
|
|
95
|
+
assert numpy_array.shape == (10, 20, 30)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_stack_numpy():
|
|
99
|
+
data = {
|
|
100
|
+
't1': np.random.rand(10, 20, 30),
|
|
101
|
+
't2': np.random.rand(10, 20, 30)
|
|
102
|
+
}
|
|
103
|
+
study = Study(data)
|
|
104
|
+
|
|
105
|
+
stacked = study.stack_numpy(scans=True, seg=False)
|
|
106
|
+
assert stacked.shape == (2, 10, 20, 30) # 2 images, each 10x20x30
|
|
107
|
+
|
|
108
|
+
@pytest.mark.parametrize("prefix", ("", "prefix"))
|
|
109
|
+
@pytest.mark.parametrize("suffix", ("", "suffix"))
|
|
110
|
+
def test_serialization(prefix,suffix):
|
|
111
|
+
data = dict(
|
|
112
|
+
t1=np.random.rand(10,20,30),
|
|
113
|
+
t2=np.random.rand(40,50,60),
|
|
114
|
+
seg_brain=np.random.randint(0,2, (10,20,30)),
|
|
115
|
+
seg_tumor=np.random.randint(0,5, (40,50,60)),
|
|
116
|
+
info_id=10,
|
|
117
|
+
info_name="Name"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
study = Study(data)
|
|
121
|
+
assert sorted(study.keys()) == sorted(["t1", "t2", "seg_brain", "seg_tumor", "info_id", "info_name"])
|
|
122
|
+
|
|
123
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
124
|
+
out_dir = os.path.join(tmpdir, "study")
|
|
125
|
+
study.save(out_dir, prefix=prefix, suffix=suffix)
|
|
126
|
+
loaded = Study.from_dir(out_dir, prefix=prefix, suffix=suffix)
|
|
127
|
+
|
|
128
|
+
assert sorted(loaded.keys()) == sorted(["t1", "t2", "seg_brain", "seg_tumor", "info_id", "info_name"])
|
|
129
|
+
|
|
130
|
+
for k, v in study.items():
|
|
131
|
+
if isinstance(v, sitk.Image):
|
|
132
|
+
assert sitk.GetArrayFromImage(v).shape == sitk.GetArrayFromImage(loaded[k]).shape
|
|
133
|
+
assert sitk.GetArrayFromImage(v).dtype == sitk.GetArrayFromImage(loaded[k]).dtype
|
|
134
|
+
assert np.all(sitk.GetArrayFromImage(v) == sitk.GetArrayFromImage(loaded[k]))
|
|
135
|
+
else:
|
|
136
|
+
assert v == loaded[k]
|
tests/test_utils.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from mrid.utils.python_utils import LazyLoader
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_lazy_loader():
|
|
6
|
+
loader = LazyLoader("os")
|
|
7
|
+
assert loader is not None
|
|
8
|
+
|
|
9
|
+
assert hasattr(loader, 'path')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_lazy_loader_nonexistent_module():
|
|
13
|
+
loader = LazyLoader("this_module_does_not_exist_12345")
|
|
14
|
+
|
|
15
|
+
with pytest.raises(ImportError):
|
|
16
|
+
_ = loader.some_attribute
|